Cygwin startup environment variables

Cygwin startup configuration is controlled by Windows environment variable CYGWIN. Not populating Cygwin PATH from Windows PATH avoids confusion from Windows programs being used instead of Cygwin programs. Set Windows environment variable:

CYGWIN_NOWINPATH=1

will result in a basic Cygwin PATH like:

/usr/local/bin:/usr/bin

Look inside Cygwin “/etc/profile” for more environment variables that may be of interest.

NOTE: all Windows environment variables are imported by Cygwin. Override these variables in ~/.bashrc or scripts if desired.

Related: don’t populate WSL PATH from Windows PATH.

Fortran logical boolean byte size

Fortran compilers typically use 4 bytes for logical while C compilers usually use 1 byte for bool. For C interoperability, Fortran can use:

use, intrinsic :: iso_c_binding

logical(kind=C_BOOL) :: L
logical :: Q

c_sizeof(L) == 1
c_sizeof(Q) == 4
! typically

while C uses:

#include <stdbool.h>
#include <stdio.h>

int main(void) {
bool L;
printf("%d\n", sizeof(L));
}

and likewise C++ bool is typically 1 byte:

#include <iostream>

int main(){
  bool L;
  std::cout << sizeof(L) << std::endl;
}

Always use iso_c_binding when using C or C++ with Fortran modules to produce cross-platform compatible projects.

See “bool” examples for interfacing between C, C++ and Fortran.

Use libutil on MacOS and Linux

Libutil gives abstractions for OS-specific TTY operations. When using these abstractions across MacOS and Linux, use this preprocessing statement for the appropriate header:

#ifdef __APPLE__
#include <util.h>
#else
#include <pty.h>
#endif

If using CMake, ensure the library and header are found:

find_library(UTIL_LIBRARY NAMES util)

if(APPLE)
  find_path(UTIL_INCLUDE_DIR NAMES util.h)
elseif(UNIX)
  find_path(UTIL_INCLUDE_DIR NAMES pty.h)
endif()

Cross-compile for DOS from Windows or Linux

OpenWatcom is an open-source C/C++ compiler that can compile for a variety of systems, particularly legacy 16/32-bit Windows and DOS systems. This can be of interest for retro gamers and those using old devices that have DOS-based software, including industrial controllers and two-way radio programming.

CMake supports OpenWatcom, and is conveniently used with a toolchain file. GitHub Actions has easy scripting for OpenWatcom to test building of DOS programs from Linux.

The easiest way to show this is by example: see the Ascii Patrol game for how to build with OpenWatcom for DOS from Windows/Linux and GitHub Actions build CI.

Force older language standard in CMake

CMake target_compile_features sets a transitive MINIMUM language standard necessary. If the compiler defaults to a newer language standard, target_compile_features allows that default. This can make issues for legacy code that requires an older language standard. For example, an old C++98 code may need to have the compiler in C++98 mode. This is accomplished with the target property CXX_STANDARD. Other languages may have a similar property.

Example: C++98 needed for old code:

set_target_properties(old PROPERTIES CXX_STANDARD 98)

ssize_t for Visual Studio

The POSIX C type “ssize_t” is available on Unix-like systems in unistd.h. For Windows Visual Studio based compilers without unistd.h, the following stanza allows use of ssize_t.

#ifdef _MSC_VER
#include <BaseTsd.h>
typedef SSIZE_T ssize_t;
#else
#include <unistd.h>
#endif

CMake import interface link

CMake can add interface linking to imported libraries. For example, a imported library obtained by find_package() or otherwise. Normally, this would work like the following example to say link “stdc++fs” to example imported library “imported::lib” for GCC older than 9.1.

if(CMAKE_CXX_COMPILER_ID STREQUAL GNU AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.1.0)
  target_link_libraries(imported::lib INTERFACE stdc++fs)
endif()

Function target_link_libraries() should work, but does not always work for some projects with a configure time error. To workaround this issue if it arises, set target property INTERFACE_LINK_LIBRARIES directly like:

set_target_properties(imported::lib PROPERTIES INTERFACE_LINK_LIBRARIES stdc++fs)

CMake CTest single command build and test

Many CMake users have muscle memory for the three-stanza configure, build, test with CMake:

cmake -B build
# configure CMake and generate build files

cmake --build build
# compile and link binaries

ctest --test-dir build
# run program self-tests

This can be reduced to a single command for many programs:

ctest -S setup.cmake

where a single file setup.cmake is added to the project.

Command-line options like “-Dvar=yes” must be aggregated and passed along to ctest_configure(OPTIONS) in setup.cmake.

Get CPU count from Matlab

Capture the number of physical CPU cores available on a computer from Matlab:

function N = get_cpu_count()
%% get apparent number of physical CPU cores

N = maxNumCompThreads;
if N < 2  % happens on some HPC
  N = feature('NumCores');
end

end

Related: Python CPU count

Install Nvidia HPC C, C++, Fortran compilers

The free-to-use Nvidia HPC SDK is indicated to build systems by environment variables:

CC=nvc
CXX=nvc++
FC=nvfortran

Ensure the HPC SDK bin/ directory is in environment variable 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 current language standard support: C11, C++17. Fortran 2003 standard with some Fortran 2008 including submodule and error stop.

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

Cmake: set compiler-specific options in CMakeLists.txt like:

project(myproj Fortran)

if(CMAKE_Fortran_COMPILER_ID STREQUAL NVHPC)
  add_compile_options($<$<COMPILE_LANGUAGE:Fortran>:-Mdclchk>)
endif()