Scientific Computing

Git difftool / mergetool with Visual Studio Code

Many developers already use Visual Studio Code, which is a free open-source program available for Linux, macOS and Windows. VS Code can do Git 3-way merge.

VS Code for Git difftool and mergetool:

git config --global diff.tool vscode

git config --global merge.tool vscode

git config --global difftool.vscode.cmd "code --wait --diff \$LOCAL \$REMOTE"

git config --global mergetool.vscode.cmd "code --wait --merge \$REMOTE \$LOCAL \$BASE \$MERGED"

Note the backslashes so that the shell doesn’t gobble the “$” variables before they’re saved to user global ~/.gitconfig.

This process assumes that VS Code shell command is setup.


Alternative: Meld

Intel oneAPI / Visual Studio debug library build

On Windows, when building an executable target in Debug mode using Visual Studio or Intel oneAPI, it may be necessary to also have the libraries linked by the target to have Debug symbols. For example, when building in CMake:

cmake -B build -DCMAKE_BUILD_TYPE=Debug

cmake --build build --config Debug

This may be indicated by messages like:

error LNK2038: mismatch detected for '_ITERATOR_DEBUG_LEVEL': value '0' doesn't match value '2' in main.cpp.obj

error LNK2038: mismatch detected for 'RuntimeLibrary': value 'MD_DynamicRelease' doesn't match value 'MDd_DynamicDebug' in main.cpp.obj

The solution is to build the libraries with Debug mode as well.

Homebrew vs. MacPorts package managers

macOS package managers allow easy download, build and install of developer programs and libraries.

Homebrew is by far the most popular macOS package manager. Homebrew has a large number of packages and the ability to create unofficial “taps” to easily distribute software. Homebrew taps allow distributing binaries via Homebrew before going to include in the main homebrew package repo, which takes time and justification. Homebrew distributes per-OS compiled binaries, so package install time is almost instant. It is possible to also download source and build locally with Homebrew if desired.

MacPorts generally distributes source code that is compiled on install, although it can also use precompiled binaries. Macports installs packages under a prefix.

Homebrew is much more popular than MacPorts or Fink.

Package popularity comparison:

CMake find with Homebrew

Anaconda Python puts itself first on PATH when activated. This can become a problem for libraries like HDF5, where “conda install h5py” puts compiler script h5cc on environment variable PATH before the intended script path. For systems where Homebrew is used to provide packages to find from CMake, tell CMake to prefer a package location with CMAKE_PREFIX_PATH.

export CMAKE_PREFIX_PATH=$(brew --prefix)

CMake Git inactivity timeout

CMake Git operations such as shallow clone can cause unexpected failures due to too small INACTIVITY_TIMEOUT in ExternalProject or FetchContent. Be sure to set INACTIVITY_TIMEOUT to a large enough value. 15 seconds is too short a timeout for Git shallow clone, for example. Consider 60 seconds or larger INACTIVITY_TIMEOUT.

Check for timeout in:

git config --get http.lowSpeedLimit
git config --get http.lowSpeedTime

lowSpeedLimit might be set to 1000 (bits/second) or as appropriate for the network. If lowSpeedTime is too short, this download failure can also occur. Set to 60 seconds or more.

CMake generator full path

Normally it is not necessary to specify the path to the CMake generator backend, assuming the generator executable is in environment variable $PATH or CMAKE_PROGRAM_PATH. For special use cases such as testing CMake with different versions of a generator the generator executable absolute path may be specified via CMAKE_MAKE_PROGRAM. The absolute path to the generator is necessary or CMake will not find it.

Suppose a GitHub Actions Linux image has ninja-linux.zip containing executable file “ninja”. Get the absolute path using realpath.

    - run: unzip ninja-linux.zip

    - name: CMake configure
      run: cmake -G Ninja -DCMAKE_MAKE_PROGRAM=$(realpath ./ninja) -Bbuild

CMake FindPython hints

CMake Find modules are by their nature a little aggressive about finding libraries and executables. This becomes a factor on Windows in particular when Anaconda Python is not active in the current Terminal. CMake find_package(Python) by default prefers Anaconda Python over system Python unless overridden as below. Anaconda Python won’t operate correctly without conda activate, which presumably the user has either forgotten to do or doesn’t desire at the moment. To decrease the aggressiveness and find Windows Store Python etc. when conda isn’t activated on Windows, add to the project CMakeLists.txt before find_package(Python):

set(Python_FIND_REGISTRY LAST)
# this avoids non-active conda from getting picked anyway on Windows

set(Python_FIND_VIRTUALENV STANDARD)
# Use environment variable PATH to decide preference for Python

find_package(Python)

Disable conda auto activate base

Anaconda Python by default auto-activates the “base” environment each time a new Terminal is opened. This slows opening new Terminal, particularly on systems with slow disks or virtual disks. Particularly if the user isn’t constantly using Python, it can be beneficial to make conda only active when specified. To disable conda auto-activation on new Terminal, type:

conda config --set auto_activate_base false

This setting takes effect in .condarc

Fortran compiler standard enforce

Fortran compilers typically have options for enforcing Fortran standards. The compilers raise additional warnings or errors for code that is not deemed compliant. Fortran standard options can make false warnings, so we generally do not enable standards checking for user defaults. However, we do enforce implicit none as a quality measure.

It’s also important to use implicit none so that each variable must be assigned beforehand. We recommend the Fortran 2018 statement:

implicit none (type, external)

which requires explicitly defined procedure interfaces as well.

type
the traditional implicit none default
external
new for Fortran 2018, requires explicit interface for external procedures.

GCC Gfortran -std=f2018 enforces Fortran 2018 standard. Consider these Gfortran options:

gfortran -Wall -fimplicit-none

Intel oneAPI -stand f18 enforces Fortran 2018 standard. Consider these options that also enforce implicit none:

ifx -warn

Cray Fortran compiler enforces implicit none via option:

ftn -eI

note that’s a capital “I” not a lowercase “ell”.

Nvidia HPC Fortran compiler enforces implicit none via:

nvfortran -Mdclchk

NAG Fortran has -f2018 Fortran 2018 flag. Enforce implicit none by:

nagfor -u

CMake logic to enforce these standards:

if(CMAKE_Fortran_COMPILER_ID STREQUAL "Cray")
  add_compile_options("$<$<COMPILE_LANGUAGE:Fortran>:-eI>")
elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "GNU")
  add_compile_options(-Wall "$<$<COMPILE_LANGUAGE:Fortran>:-fimplicit-none>")
elseif(CMAKE_Fortran_COMPILER_ID MATCHES "^Intel")
  add_compile_options("$<$<COMPILE_LANGUAGE:Fortran>:-warn>")
elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "NVHPC")
  add_compile_options("$<$<COMPILE_LANGUAGE:Fortran>:-Mdclchk>")
elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "NAG")
  add_compile_options("$<$<COMPILE_LANGUAGE:Fortran>:-u>")
endif()