Create Jekyll GitHub or GitLab hosted website

GitHub, GitLab, Bitbucket and similar services allow free, fast static websites under usage limits:

GitHub Pages is noticeably easier to use than GitLab or Bitbucket Pages. GitLab runners are slow and build quota can run out before month’s end. Most should start with GitHub Pages for websites of any size.

Create Jekyll website

The Minimal Mistakes Jekyll template is one of numerous quick-loading Jekyll templates. Forget about AMP, get lightning-fast mobile browsing Google PageSpeed scores with Jekyll and Minimal Mistakes. This procedure is based on Linux (including Windows Subsystem for Linux).

  1. get prereqs

    apt install ruby-dev libssl-dev
    gem update --system
  2. Configure Ruby Gem install without sudo

  3. install Gem bundler (without sudo):

    gem install jekyll bundler
  4. Download and extract latest Minimal Mistakes release.

  5. Install needed Gems:

    mv minimal-mistakes
    bundle install

    username : your GitLab or GitHub username

  6. On GitHub/GitLab, create a new blank repository (for GitLab,

  7. Edit _config.yml, change the following lines to fit your needs: title, name, description, url, repository

  8. Connect your new website to GitLab/GitHub (swapping gitlab for github as appropriate)

     git init
     git add .
     git commit -am init
     git remote add origin https://github.invalid/username/
     git push -u origin master

Future edits will follow the usual

git commit -am foo
git push

Now your page should be live at See Github Pages docs for custom domains and advanced configs.

Writing blog posts

Folders under _posts with filenames starting with date appear on the site. Subfolders under _posts are transparently processed. This is useful to organize posts by year for example, without affecting URL formatting.

Example filename: _posts/2018/ appears to the public with URL:

Jekyll Format tip

These tips are based on the Minimal Mistakes Jekyll theme

Enable search icon

in _config.yml

search: true

This enables site-wide Lunr instant search as the user types. The search icon is at the upper right corner of the toolbar on top of every page/post. It’s much better/faster than Google-based search of your site! This instant as-you-type search scales well for sites with thousands of pages.

remove default “layout: post” from migrated posts

This is useful for the default layout: single in _config.yml below.

sed -i '/layout: post/d' *.html

static nav buttons

edit _data/navigation.yml

Nice formatting

copy/paste into _config.yml these lines (anywhere in file):

      path: ""

      layout: "single"
      toc: true
      author_profile: false
      read_time: false
      comments: true
      share: true
      related: true

include: ["_pages"]

Beautiful banner

add to index.html header (between three dashes) the lines:

    overlay_color: "#000"
    overlay_filter: "0.5"
    overlay_image: /images/header.jpg
excerpt: "text overlaid on banner image"

Remote author image


author_profile: false

It’s smart to do this in case you later decide a page category should change, without screwing up your search engine results.


permalink: /:title/

number of posts per archive page


paginate: 10 # amount of posts to show


Jekyll install reference

Academic / professional web profile page

GitLab Pages vs. GitHub Pages

site generatoranyJekyll only
Jekyll pluginsanyonly allowed
  • GitHub Pages is substantially easier to setup and use, and is capable of medium websites getting several million hits / year
  • GitLab Pages has more features and flexibility for advanced users

GitLab Pages quick setup

  1. create a new GitLab Project named (put your GitLab username in for “username”)
  2. [if you already have a GitHub Pages website] Import from GitHub OR create/copy in your existing static website (if you had a GitHub Pages website, copy it here). If the latter, clone to your PC.
  3. on the GitLab project page e.g. click Set up CI
  4. Create the .gitlab-ci.yml under the apply a GitLab CI YAML template. If coming from GitHub Pages use Jekyll.
  5. The site is now building as seen with the Pipelines tab of your website project. It takes about 3-4 minutes to install the gems for a Jekyll site, then 2-3 more minutes to complete the build depending on the size of your website. The public URL should be

Custom domain

If a custom domain was purchased, tie to GitLab Pages by:

Project Settings → Pages add TWO new domains


transfer DNS to GitLab

This step can take the website down so do this at low traffic times.

Once ready, setup/transfer DNS to GitLab. Suppose the domain is example.invalid, then set DNS records to

example.invalid CNAME
www             CNAME

assuming the DNS provider supports CNAME flattening such as Cloudflare.

SSL Config

GitLab Pages used with for example Cloudflare works well to provide HTTPS with your custom domain name as per this procedure. With that procedure you can enable SSL “Full (Strict)” security.

Update limits

Free GitLab accounts have a monthly quota for build “pipeline” time. For a small to moderate size static website it should be enough. Save quota by canceling pipelines / runs for wasted builds.

For frequently updated, medium sized websites (hundreds or thousands of pages) consider Netlify with GitLab Pages or GitHub Pages.

Private source repo

Both GitLab and GitHub allow the source files (e.g. Markdown) to be private for a public website. Consider a private website repo, otherwise Google may present search results from Markdown code before the actual webpage.


  • For larger or active websites use Netlify, or build on laptop or cloud service like Wercker with any static generator such as Hugo and push HTML to GitHub Pages
  • Useful Jekyll plugins that GitHub doesn’t allow include jekyll-archives (page per category/tag)
  • GitLab Pages from scratch
  • Netlify works well with GitHub or GitLab, adding speed and reliability among other benefits
  • tips for academic / professional web profile pages

Fix Fitbit not syncing

The Fitbit app on certain phones with certain devices can sometimes fail to sync. This might happen a couple times a month. To workaround this issue, try force stopping the Fitbit app. This normally shouldn’t lose any data, and reopening the Fitbit app and dragging down should re-sync in a few seconds.

Also, check that Bluetooth is enabled on the Android device.

Force stop Android app

Force stop an Android app by:

Settings → Apps and Notification → Sell all apps → scroll to app name and click → click Force Stop

Specify shell script interpreter

In general it is not appropriate to assume the default shell is Bash. Using a generic script shebang:


will either:

  • use the default shell (which could be one of many shells)
  • invoke legacy Bourne Shell 1980s compatibility mode of your shell

Either way, a shell script using the general #!/bin/sh may fail on other computers. To improve shell script robustness, specify a particular shell with the shebang. Many Linux distros default to shells like:

To have even better cross-platform robustness, consider using Python instead of shell scripts.

Specify shell to run script

The default Linux shell is selectable in the shebang in the first line of the “” shell script. For example, to specify Bash shell, put as the first line:


What is current shell

echo $SHELL

this $SHELL variable may not strictly be the “default” shell if you have scripts changing the shell on interactive login. Other users may choose a different default shell.

run script in specific shell

To run a script in a specific shell, do like:


change default shell

To permanently change a user default shell on Linux, MacOS or Windows Subsystem for Linux, use chsh.

Using CMake on Windows

Similar to Linux, CMake on Windows is installed by extracting the cmake* .zip file and adding the new …/bin to PATH environment variable. We use the Ninja build system with CMake, which is generally faster on any platform and in particular for Windows solves numerous issues.

Compile programs using CMake

Navigate to the directory containing the file CMakeLists.txt using the Windows Terminal / Command Prompt.

  1. configure the build. This is normally run only once unless making major project changes.
cmake -B build
  1. compile the program. This is the command run each time you make a change to the project code.
cmake --build build
  1. Optionally, install the program with
cmake --install build

Generator selection

On Windows, CMake defaults to Visual Studio and Nmake–the CMAKE_GENERATOR environment variable suggested above overrides CMake defaults. CMAKE_GENERATOR can also be overridden like:

cmake -G "Visual Studio 16 2019"

sh.exe error with cmake

This error is fixed by upgrading to CMake ≥ 3.17.

sh.exe was found in your PATH, here: C:/Program Files/Git/user/bin/sh.exe For MinGW make to work correctly sh.exe must NOT be in your path. Run cmake from a shell that does not have sh.exe in your PATH. If you want to use a UNIX shell, then use MSYS Makefile


Matlab MinGW / Intel compiler setup

Matlab requires C / C++ / Fortran compilers for numerous operations such as mex, loadlibrary and more. For Windows, besides Visual Studio, Matlab supported compilers include MinGW GNU compilers for Windows for C and C++, or Intel oneAPI compilers for C / C++ / Fortran.

If Matlab doesn’t detect MinGW compiler location, you may get an error like

Error in loadlibrary>getLoadLibraryCompilerConfiguration


Error using mex No supported compiler was found.

Tell Matlab compiler location

Matlab uses distinct environment variables to communicate the location of specific compiler versions. Here are a couple examples. On Windows, Matlab will use Visual Studio and Intel oneAPI compilers.

MinGW compiler

Tell Matlab the MinGW compiler path via Windows environment variable MW_MINGW_LOC. On Windows, Fortran needs Intel oneAPI compiler instead.

  1. Find the MinGW compiler location from Terminal using where gcc (Windows) or which gcc.

  2. in Matlab, assuming MinGW is under C:\mingw64\bin (don’t include “bin” below)

    setenv('MW_MINGW64_LOC', 'c:\mingw64')
  3. Setup MEX C / C++ permanently

    mex -setup -v
    mex -setup -v C++

Intel compiler

Intel oneAPI Fortran compiler with Matlab is setup by:

mex -setup Fortran -v
mex -setup -v

If the Intel oneAPI compilers are not found:

  1. find the Intel compiler location using where ifort (Windows) or which ifort.

  2. assuming compiler location is at “C:\Program Files (x86)\inteloneapi\compiler\latest\windows\bin\intel64\ifort.exe”

    set('ICPP_COMPILER19', 'C:\Program Files (x86)\inteloneapi\compiler\latest\windows')
    set('IFORT_COMPILER19', 'C:\Program Files (x86)\inteloneapi\compiler\latest\windows')


Matlab MEX parameters are displayed in Matlab by:




Matlab package import like Python

Matlab users can package code projects as toolboxes and/or packages. The packages format works for ancient versions of Matlab, before even R2006a as well as GNU Octave. The toolbox format works for Matlab ≥ R2016a and not GNU Octave. The packages format brings benefits to toolboxes as well.

Matlab namespaces

A key issue with Matlab vs. Python arise from that Matlab users often add many paths for their project. If any function names clash, there can be unexpected behavior as it’s not immediately clear which function is being used without further investigation of path ordering. As in Python and other languages, there is considerable benefit for using a package format where the function names are specified in their namespace.

addpath example

To enable Matlab package format, we explain by example. Suppose a project directory structure is like:


To use these functions, the end users do:


This is where the namespace can have clashes, and with large projects it’s not clear where a function is without further introspection.

package example

To make this project a Matlab / Octave package, change the subdirectories containing .m files to start with a “+” plus symbol:


Now the end users will simply:


and then access specific functions like:


Then multiple subdirectories can have the same function name without clashing in the Matlab namespace. Support the function “mem1” is used frequently in another function. To avoid typing the fully resolved function name each time, use the import statement:

function myfunc()

import myproj.utils.mem1



Matlab toolbox .mltbx

Matlab .mltbx toolboxes became available in R2016a. The Matlab-proprietary toolbox format also allows end users to create their own packages containing code, examples and even graphical Apps. In effect .mltbx provides metadata and adds the package to the bottom of Matlab path upon installation. The installation directory is under (system specific)/MathWorks/MATLAB Add-Ons/Toolboxes/packageName. Whether or not the project uses .mltbx, the namespace of the project is kept cleaner by using a Matlab package layout.

Intel MPI on Windows

On Windows, the Intel C, C++ and Fortran compilers present Visual Studio-like command line options. The correct version of Visual Studio must be installed on Windows for Intel compilers to work. C and C++ use the icl compiler on Windows.

The free Intel oneAPI with HPC toolkit includes the Intel MPI library, which provides mpiexec needed to run MPI programs and MPI compiler wrappers.

Loading Intel compiler environment

Most users use the Intel oneAPI command prompt. Alternatively, run “compilervars.bat” script to enable the Intel compilers for each session. “psxevars.bat” is not appropriate for this setup. For convenience, make a batch script like %userprofile%\intel.bat containing:

"C:\Program Files (x86)\inteloneapi\compiler\latest\windows\bin\compilervars.bat" intel64

set FC=ifort
set CC=icl
set CXX=icl

Intel MPI on Windows is only for Intel compiler

Unlike for Linux Intel MPI, Windows Intel MPI is only for the Intel C, C++ and Fortran compilers and Visual Studio.


Although not often needed, a separate username can be used for Windows Intel MPI jobs by from Command Prompt:

runas /user:username cmd

Environment variables are not passed to the new window, so it may be necessary to run Intel compilervars.bat again. It’s possible to register the user credential in the Windows registry.

Major changes in Gfortran by version

Gfortran and Intel oneAPI are the most advanced modern Fortran compilers. Useful Fortran 2018 enhancements include:

oldest Gfortran version

Gfortran 8 is the oldest version currently maintained.

Intel oneAPI

  • Intel oneAPI has “full” Fortran 2018 support.

Gfortran major changes

Gfortran 10

  • select rank – making assumed rank arguments actually useful.

Gfortran 9

  • added random_init() to initialize the random generator seed…randomly

Gfortran 8.1

  • Optimization: automatic nested loop exchange with do concurrent
  • Checks: Actual argument array with too few elements for dummy argument now errors
  • Polymorphism: initial support for parameterized derived types (simply define kind at initialization)
  • Coarray: Initial support for teams

(Gfortran 8.2 and 8.3 did not introduce new Fortran features)

Gfortran 8

  • std=f2008ts deprecated, do not use as it errors on compiling error stop for Gfortran < 8.
  • std=f2018 added

Gfortran 7

  • Polymorphism: derived type IO select type etc. fully supported from Fortran 2003.
  • Fortran 2018: Non-constant stop and error stop codes
  • Compatibility: -fdec- options help compiling very old non-standard code that was previously only compatible with Intel oneAPI (of DEC heritage).

Gfortran 6

Fortran 2008: submodule support, useful for large projects to save compilation time and allow powerful use scenarios

Fortran 2003: improved support for deferred-length character. These are very useful for avoiding bothersome trim() everywhere. Example:

character(256) :: argv
character(:), allocatable :: filename

call get_command_argument(1, argv)
filename = trim(argv)

end program

In this example, filename is now exactly the length required to fit the text. If the filename (in argv) was “hello.txt” then len(filename) is 9. That is, len_trim == len with auto-allocated characters (unless subsequently rewritten with a shorter string).

Practical examples are in gitrev.f90 and split_string.f90. For split_string.f90, note that this is the proper way to avoid assumed-length character functions, which are obsolete as of Fortran 95. Specifically:


! don't do this!
character(*) function myfun(a)


pure function myfun(a)
character(:), allocatable :: myfun

Gfortran 5

  • OpenMP 4.0 fully supported
  • Fortran 2003: ieee_ intrinsics supported, allowing convenient standard-compliant use of nan, ieee_is_nan, etc.
  • Fortran 2008: Initial coarray support
  • Fortran 2008: error stop in pure procedures, but only without specifying std= (until Gfortran 8 std=f2018). Error code must be constant.

Gfortran 4.9

  • Fortran 2003: allow deferred-length character variables in derived types

Gfortran 4.8

By this release, substantial Fortran 2008 polymorphism support had been initially added, including

  • select type
  • class(*)
  • type(*)
  • assumed rank dimension(..)

Gfortran 4.6

Gfortran 4.6 is the first version of Gfortran basically usable with commonly used code beyond Fortran 95.

  • Fortran 2003: deferred-length character variable (not in derived types until 4.9)
  • Fortran 2008: impure elemental support

Gfortran 4.5

  • Fortran 2008: iso_fortran_env real64 etc. added

Gfortran 4.4

Gfortran 4.4 added initial support for polymorphism.

  • OpenMP 3

Operating system vs. Gfortran version:

Here are a few common operating systems vs. easily available Gfortran version. CentOS should use devtoolset.



Ubuntu / Debian

  • Ubuntu gfortran repo defaults

  • Get recent Gfortran via PPA

  • Ubuntu 20.04 default: gfortran-9

  • Ubuntu 18.04 default: gfortran-7

  • Ubuntu 16.04 default: gfortran-5

  • Debian Buster, including Raspberry Pi: gfortran-8


  • release 8 (EOL 2029): gfortran-8

  • release 7 (EOL 2024) devtoolset-8: gfortran-8

  • release 7 EPEL: gfortran-4.9

  • release 7 default: gfortran-4.8


CMake allows switching parameters based on compiler version. This is very useful for modern Fortran programs.

Fortran 2018

Example CMakeLists.txt for Fortran compiler version dependent options.


  # option applying to any language for this compiler

  # language-specific, note LEADING space
  string(APPEND CMAKE_Fortran_FLAGS " -fimplicit-none")

    string(APPEND CMAKE_Fortran_FLAGS " -std=f2018")


add_executable(myprog main.f90)

Non-Fortran 2018 workaround

Here we assume that assert.f90 contains error stop in a procedure that’s called from a pure procedure.

check_fortran_source_compiles("character :: a; error stop a; end"
  f18errorstop SRC_EXT f90)

add_executable(myprog PRIVATE main.f90)

  target_sources(myprog PRIVATE assert.f90)
  target_sources(myprog PRIVATE assert_old.f90)


Install Nvidia HPC free C, C++, Fortran compilers

The free-to-use Nvidia HPC SDK compiler executables are:

  • C: nvc
  • C++: nvc++
  • Fortran: nvfortran

Existing toolchains such as CMake and Meson can immediately use HPC SDK by setting environment variables:


first ensuring the HPC SDK bin/ directory is on PATH.

Nvidia HPC binaries can offer speed improvements over GNU GCC / GFortran, but Intel oneAPI binaries can be significantly faster than Nvidia-compiled binaries for CPU-only workloads. Unless one specifically needs the GPU features of Nvidia HPC SDK consider GNU or Intel oneAPI that have more modern Fortran features.

Nvidia HPC compilers are currently available for Linux, with language standard support:

  • C11
  • C++17
  • Fortran 2003, with some Fortran 2008 including submodule and error stop


  1. Download and install Nvidia HPC SDK:
  2. sudo is not required, but the install must be on symbolic-link-aware drive (not ExFAT)
  3. Add the Nvidia “bin” directory to your “~/.bashrc” PATH environment variable.
  4. Open a new terminal to use Nvidia compilers.


Currently, CMake can recognize Nvidia compilers as “PGI” since Nvidia HPC SDK takes over for deprecated PGI compilers.

Set compiler-specific options in CMakeLists.txt for various Fortran compilers like:

project(myproj Fortran)


Until CMake is updated to recognize Nvidia HPC as a distinct compiler suite, select the Nvidia compilers at CMake configure step:

FC=pgfortran CC=pgcc CXX=pgc++ cmake -B build