mdadm mount RAID

mdadm is a popular Linux tool to manage RAID arrays. RHEL provides a usage guide.

After creating a RAID array, or to find an existing array that may or may not be mounted, use commands like:

mdadm --detail /dev/md/Volume0_0

Note the individual RAID disk /dev/sd*, which can be further examined like:

mdadm --examine /dev/sda /dev/sdb

Also examine all available devices with:

fdisk --list

To mount the RAID, use commands like:

mkdir /mnt/raid
# arbitrary location you want to mount RAID device at

mount /dev/md/Volume0_0p1 /mnt/raid

There might be extra devices under /dev/md that can’t be mounted, but one of them should be the desired RAID.

Visual Studio /delayload with CMake

CMAKE_LINK_LIBRARY_USING_FEATURE is a nice addition to CMake. CMake doesn’t have a built-in special /delayload delayed load import feature for MSVC-like compilers. Nonetheless, /delayload can be accomplished in a compact way as in the following example:

add_library(my SHARED lib.c)
add_executable(main main.c)

target_link_libraries(main PRIVATE my)

if(MSVC)
  set_property(TARGET my PROPERTY WINDOWS_EXPORT_ALL_SYMBOLS true)
  target_link_libraries(main PRIVATE delayimp)
  target_link_options(main PRIVATE "/DELAYLOAD:$<TARGET_FILE_BASE_NAME:my>.dll")
endif()

CMake check path write access

CMake configure time is often a convenient time to test if a directory or file is writable. It can be useful to immediately stop with message(FATAL_ERROR) if a path is not writable. For example, if CMAKE_INSTALL_PREFIX is not in a writable location – we want to fail right then and inform users what to do to correct the problem.

file(TOUCH) and file(MAKE_DIRECTORY) do not halt the configure step. Rather, if a path isn’t writable CMake only errors at the end of configure.

Example solution:

This snippet generates a fatal error with text telling the user what to try:

set(test_path /path/to/test/.ignore)
# could be done with random string filename in the desired path

execute_process(COMMAND ${CMAKE_COMMAND} -E touch ${test_path}
RESULT_VARIABLE ret
)
if(NOT ret EQUAL "0")
  message(FATAL_ERROR "No write access to ${test_path}
  <text for user to resolve issue>")
endif()

Dynamic libraries and CMake

On Unix-like platforms, CMake variable CMAKE_DL_LIBS is populated to link with target_link_libraries(), providing functions like “dlopen” and “dladdr”. For some libdl functions it’s necessary to also define “_GNU_SOURCE” like:

add_library(mylib SHARED mylib.c)
target_link_libraries(mylib PRIVATE ${CMAKE_DL_LIBS})
target_compile_definitions(mylib PRIVATE _GNU_SOURCE)

On Windows different mechanisms can be used to access DLLs. With MSYS2 libdl is available via mingw-w64-x86_64-dlfcn.

Run path (Rpath)

On Unix-like systems, the concept of run path is the search path for libraries used by a binary at runtime. For Windows there is no separate Rpath, just PATH is used–necessary .dll files must be on PATH environment variable at the time of running a binary. For Unix-like systems life can be easier since the Rpath is compiled into a binary. Optionally, using $ORIGIN in Rpath allows relocating binary packages.

For CMake, we use these options on virtually all our projects. We have them set all the time – no need for “if()” statements.

include(GNUInstallDirs)

set(CMAKE_INSTALL_NAME_DIR ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR})
set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR})
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH true)

set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS true)

Exporting symbols for MSVC-based compilers is necessary to generate a “my.lib” corresponding to the “my.dll”.

To have the installed CMake binaries work correctly, it’s necessary to set CMAKE_PREFIX_PATH at configure time. That is, the configure-build-install sequence for shared library project in CMake is like:

cmake -Bbuild -DBUILD_SHARED_LIBS=on -DCMAKE_INSTALL_PREFIX=/opt/my_program

cmake --build build

cmake --install build

In general the rpath in a binary can be checked like:

  • Linux: readelf -d /path/to/binary | head -n 25
  • macOS: otool -l /path/to/binary | tail

References:

USB-C display adapter incompatibilities

USB-C display adapters (HDMI, DisplayPort) are a wonderful thing when they work correctly. I prefer this solution to the docking ports on old bulky laptops. A symptom is USB-C adapter works on one laptop, but not on another almost identical laptop model. Symptoms include not being detected by the operating system, to showing a black screen, or very low resolution.

The solution seems to be to stick with expensive OEM display adapters, or at least long established brands. The temptation of a cheap adapter can quickly turn to frustration or botched presentations. Another thing to watch for is cheap adapters may fail intermittently when using more than one high bandwidth feature. For example, using Gigabit Ethernet and HDMI on the cheap USB-C adapter simultaneously may fail intermittently during a conference call or teaching a class, which can be frustrating.

Workarounds

Some adapters that charge the laptop with a USB-C input for power may experience improper operations if the display adapter is plugged into the laptop while the USB-C power input is powered. This problem may persist upon re-plugging the adapter to laptop and/or power cycling the monitor and laptop. A workaround we’ve found is to unplug USB-C power input to the adapter, plug into the laptop with all the desired accessories, then finally plug USB-C power input into the adapter. That is unexpected, but has worked for us sometimes.

Check CMake TLS functioning

CMake itself is built with SSL by default. If a user mistakenly builds CMake without SSL support, this is generally not usable as the vast majority of Internet sites require SSL / TLS to function. Confusing errors result for CMake network operations like file(DOWNLOAD) in this case.

CMake ≥ 3.25 can use this simple capabilities check:

if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.25)
  execute_process(COMMAND ${CMAKE_COMMAND} -E capabilities OUTPUT_VARIABLE cap)

  string(JSON has_tls GET ${cap} "tls")

  message(STATUS "${CMAKE_COMMAND} TLS available: ${has_tls}")
endif()

For older CMake, or to progamatically confirm that TLS and certificates are working, consider check_tls:

CMake resolve cyclical static link

CMake can automatically determine linker grouping via LINK_GROUP that adds linker flags like GCC:

-Wl,start-group

to static link cyclically dependent targets .

Alternatives

Target LINK_INTERFACE_MULTIPLICITY doesn’t always work. CMake docs suggest the trickiest cyclical static link cases may require Object Libraries as discussed in the next section.

A project had three targets (static libraries) that were always used like:

libfoo.a libfooC.a

or

libfoo.a libfooFortran.a

and the target code reference each other extensively, such that the linker gives up when ld –start-group isn’t used. Meson build system also adds --start-group ld option automatically.

To keep the targets with distinct compile definitions (including for “foo_src”), we used CMake Object Libraries:

add_library(tmp OBJECT ${foo_src})

add_library(fooC ${c_src} $<TARGET_OBJECTS:tmp>)
add_library(fooFortran ${fortran_src} $<TARGET_OBJECTS:tmp>)

Note, there is no “libtmp” created–only the object files from the “foo_src” will be created.

Install Windows Subsystem for Linux

Windows Subsystem for Linux WSL has available Ubuntu LTS releases among other Linux distros on the Microsoft Store, which is the recommended method to install WSL. If the Microsoft Store isn’t available on the computer due to corporate policy etc., manual WSL install is also available – but use the Microsoft Store if possible. The WSL changelog shows the continually expanding feature set.

WSL can use GUI and sound with programs like Spyder via WSLg.

List WSL distros already installed on the computer from PowerShell / Command Prompt:

wsl --list --verbose

Install, list, and switch between Linux distros on Windows default for bash from Command Prompt:

wslconfig

WSL configuration

Limit the amount of RAM WSL2 can use by editing Windows file ~/.wslconfig to include:

[wsl2]
swap=0GB
memory=4GB  # arbitrary, set to less than your total computer physical RAM to help avoid using Windows swap

A WSL default that is confusing and slows down WSL program-finding is stuffing Windows PATH into WSL PATH. We normally disable Windows PATH injection into WSL, because it also breaks library finding in build systems like CMake. Additionally, we enable filesystem metadata, as weird permission errors can occur, even causing CMake to fail to configure simple projects.

Each Linux distro has its own /etc/wsl.conf We typically include in our /etc/wsl.conf:

[automount]
enabled = true
options = "metadata"

[interop]
enabled=false
appendWindowsPath=false

The Windows file ~/.wslconfig file sets parameters for all Linux distros, versus the per distro /etc/wsl.conf discussed above. To avoid the use of Linux swap and excessive memory thrashing we include in Windows ~/.wslconfig:

[wsl2]
swap=0GB

Run Ubuntu apps from Windows Command Prompt or PowerShell:

wsl ls -l

Run Windows program from Ubuntu terminal:

/mnt/c/Windows/System32/notepad.exe

Note that capitalization matters and .exe must be at the end.

Five free C C++ Fortran compiler families

Five modern, currently-supported compiler families are free-to-use for C, C++ and Fortran.

GCC has broad support of modern standards on a very wide range of computing platforms. GCC’s downside in some cases can be slower runtime performance than compilers having less broad language and platform support.

CompilerCC++Fortran
GNUgcc: C17g++ C++20gfortran: F2018
Intel oneAPIicx: C17icpx: C++20ifx: F2018
LLVMclang: C17clang++: C++20flang-fl8: F2018
NVidia HPC SDKnvc: C11nvc++: C++20nvfortran: F2003
IBM OpenXLxlc: C11xlc++: C++14xlf: F2008

Intel oneAPI compilers are free to use for any user. The Intel performance libraries like MKL, IPP, and TBB are available at no cost.

LLVM Clang and Flang have significant industry support, including from Nvidia, and are known for high performance.

Nvidia HPC SDK is free to use. A key feature of the HPC SDK compilers is intrinsic support for CUDA Fortran.

IBM OpenXL LLVM-based compilers are currently for POWER CPUs only e.g. ppc64le. IBM OpenXL compilers do not work with a typical x86-based computer.