CMake detect if project is top level

CMake can detect if a project is “top level” that is, NOT via FetchContent using PROJECT_IS_TOP_LEVEL and PROJECT_NAME_IS_TOP_LEVEL . For simplicity, we denote these variables in this article as “*_IS_TOP_LEVEL”.

Example use:

if(PROJECT_IS_TOP_LEVEL)
  message(STATUS "${PROJECT_NAME} directly building, not FetchContent")
endif()

For CMake < 3.21, “PROJECT_IS_TOP_LEVEL” can be set like:

if(CMAKE_VERSION VERSION_LESS 3.21)
  get_property(not_top DIRECTORY PROPERTY PARENT_DIRECTORY)
  if(NOT not_top)
    set(PROJECT_IS_TOP_LEVEL true)
  endif()
endif()

Caveats

Directory property PARENT_DIRECTORY and *_IS_TOP_LEVEL are NOT useful for detecting if the child project is being used as an ExternalProject.

These variables are based on the last “project()” command and so are not as universally useful as it first seems. For example, these variables do not work as expected when using ExternalProject. Even setting CMAKE_CACHE_ARGS of ExternalProject does not help, nor does cmake (1) command line options–the CMake-internal setting of *_IS_TOP_LEVEL overrides this attempt to set it. To workaround this, use an arbitrary auxiliary variable to detect if the project is top level.

Example:

Top-level CMakeLists.txt:

ExternalProject_Add(sub1
...
CMAKE_ARGS -DSUB1_IS_TOP:BOOL=false
)

ExternalProject_Add(sub2
...
CMAKE_ARGS -DSUB2_IS_TOP:BOOL=false
)

Subproject CMakeLists.txt

if(DEFINED SUB1_IS_TOP)
  set(SUB1_IS_TOP_LEVEL ${SUB1_IS_TOP})
endif()

Rather than try to directly workaround all the corner cases of *_IS_TOP_LEVEL, using this auxiliary variable allows the user to clearly force the intended behavior. This is useful when the subprojects and main project can build required ExternalProjects, and you want to only build the required ExternalProjects once.

Git SSH Public key Authentication

Git hosting services including GitLab and GitHub can use Git over SSH for enhanced security.

Setup the file “~/.ssh/config” for Git SSH Public Key authentication like:

Host *
   IdentitiesOnly yes
   PubKeyAuthentication yes
   Port 22

Host gist.github.com
  User git
  IdentityFile ~/.ssh/github

Host github.com
  User git
  IdentityFile ~/.ssh/github

Host gitlab.com
  User git
  IdentityFile ~/.ssh/gitlab

if needed, set file permissions (non-Windows OS):

chmod 400 ~/.ssh/config

Create Git SSH key like:

ssh-keygen -t ed25519 -f ~/.ssh/github

For speed, consider Git pull over HTTPS, Git push over SSH.

Multiple accounts on same Git service

To use Git with SSH and multiple public keys e.g. for same Git server with multiple accounts, setup the file “~/.ssh/config” like:

Host github-work
    HostName github.com
    User git
    IdentityFile ~/.ssh/github-work

Host github-personal
    HostName github.com
    User git
    IdentityFile ~/.ssh/github-personal

Then clone the repository like:

git clone github-work:username/repo.git

# or

git clone github-personal:username/repo.git

To set the username and email distinct for this repo if desired, from that repo directory:

git config user.name "Your Name Here"
git config user.email your@email.invalid

PowerShell grep files

PowerShell has functionality somewhat like grep. Use regular expressions to find matching text in files and piped text using Select-String.

Grep files:

Get-ChildItem -Path . -Filter *.txt -Recurse | Select-String -Pattern 'foo'

Grep specific file:

Select-String -Path CMakeLists.txt -Pattern 'project'

Grep piped text:

cat CMakeLists.txt | Select-String -Pattern 'project'

Grep piped text with regex:

cat CMakeLists.txt | Select-String -Pattern 'project\s*\('

Make a grep() function in PowerShell by saving the following to a file “grep.ps1”. To use this function in PowerShell command line, source the file with . grep.ps1 and then use the function from the PowerShell command line like grep pattern filename. One could make this function fancier to be more grep-like.

function grep($pattern, $path) {
    Select-String -Path $path -Pattern $pattern
}

Windows cmd.exe & was unexpected at this time

A botched program install, upgrade, or install such as Anaconda Python can make a Windows registry mis-entry that causes many commands to fail. The symptoms may include that simply trying to run “cmd.exe” COMSPEC fails with message including:

& was unexpected at this time

If this message occurs even when just opening a new Command Prompt window, the problem may be that the Windows Registry AutoRun is messed up. Check this in Registry Editor under:

HKCU\Software\Microsoft\Command Processor\AutoRun

and / or

HKLM\Software\Microsoft\Command Processor\AutoRun

On one system there was a bad entry:

if exist & if exist "%USERPROFILE%\miniconda3\condabin\conda_hook.bat" "%USERPROFILE%\miniconda3\condabin\conda_hook.bat"

It was fixed by correcting to:

if exist "%USERPROFILE%\miniconda3\condabin\conda_hook.bat" "%USERPROFILE%\miniconda3\condabin\conda_hook.bat"

Visual Studio Code shell command install

On Windows, VS Code “code” shell command is enabled by default when installing VS Code:

winget install -e --id Microsoft.VisualStudioCode

The installer program adds to “Path” environment variable like:

%USERPROFILE%\AppData\Local\Programs\Microsoft VS Code\bin

That directory contains “code.cmd” that invokes “Code.exe” in the directory above. This technique avoids DLL Hell due to to the .dll files in the path above interfering with other programs if that folder was on Path.

For macOS, install VS Code shell command by pressing Shift P . For Linux the keys are Shift Ctrl P . Start typing “shell command”. Select “Shell Command: Install ‘code’ command in PATH”. This allows starting VS Code from Terminal by typing code.

RHEL SSH remote desktop VNC

RHEL adds a few complexities on top of the “plain” Debian-based Linux distros. SELinux in particular is another layer to consider. Here are common considerations for settings up SSH and/or VNC on RHEL, CentOS or similar RHEL-derived Linux distro.

For SSH connection problems, consider adding to /etc/ssh/sshd_config:

LogLevel DEBUG

then:

systemctl restart sshd.service

then:

journalctl -f

and try to login. This will print a good amount of information streaming and helps reveal .ssh/authorized_keys permissions issues and more.

To determine if SELinux is causing an issue, as a last resort one may temporarily and carefully edit /etc/selinux/config to have

SELINUX=permissive

and reboot. Be sure to put that back to enforcing and reboot when done.

Check that firewalld is allowing the desired SSH port through.

tcpdump port 22 -n -Q inout

should show packets from the client–if not the SSH server firewall may be blocking them.

Waypipe remote desktop

In general current VNC servers are not compatible with the Wayland desktop (that replaces X11). Waypipe is a new remote desktop tool that works with Wayland. However, Waypipe requires another Linux machine with Wayland, so it doesn’t work with Windows or macOS natively. If permissible for your system, you may wish to switch the desktop to X11 instead of Wayland so that traditional VNC servers work.

X11 VNC server

If you are able to switch to X11, then you can use a traditional VNC server like TigerVNC.

Switch to X11 desktop on the server by editing /etc/gdm/custom.conf:

[daemon]
WaylandEnable=false
DefaultSession=gnome-xorg.desktop

Then reboot. Ensure you can locally logon to the X11 desktop as usual.

Install TigerVNC server:

sudo dnf install tigervnc-server

Ensure username is specified with a display number in file: “/etc/tigervnc/vncserver.users”. You do not need or want a file ~/.vnc/xstartup or ~/.vnc/config.

Enable SELinux VNC server:

ausearch -c 'vncsession' --raw | audit2allow -M my-vncsession

semodule -X 300 -i my-vncsession.pp

Set a password for the VNC server:

vncpasswd

Then start the VNC server:

systemctl enable --now vncserver@:2

Logoff the local server, otherwise when you try to view VNC, it will just show a black screen. If you are logged on remotely and try to login locally, the local login gets a black screen. If this happens, you can logout the unwanted black-screen sessions by:

who -u

# gives PID of the local user (:1)

then:

kill <PID of local user>

Reference: RHEL Remote desktop

Apt no install recommends default

Apt can be set to not install recommended packages by default, which can be useful for headless embedded systems or WSL. Create a file like “/etc/apt/apt.conf.d/95-no-install-recommends” with the following contents:

apt::install-recommends "false";

This can save 100s of MB or more, which can be important for embedded systems or WSL to save time and disk space. The caveat is that some expected features may be missing. To override this setting at the command line, to install recommended packages add “–install-recommends” to the apt command line.

Locate Git submodule config file

Git submodules don’t put their individual Git config file under .git/config. This Git command issued from the Git submodule directory tells the file path to the Git submodule config file:

git rev-parse --git-path config

Say a repository “alpha” has submodule “beta”. Find the Git config file location of “beta” from “alpha” like:

git -C beta rev-parse --git-path config

# OR

cd beta
git rev-parse --git-path config

ImageMagick memory limits

NEXRAD preview PNGs are 12200 x 5400 pixels: example This takes over 650 MB of RAM to load each frame.

ImageMagick -limit option can be used to limit the amount of RAM and/or disk used by ImageMagick operations. For example, if processing images on an embedded systems like a Raspberry Pi, the limited RAM may lead to disk swapping, taking 1000x longer or failing anyway. Use combinations of -limit options to control RAM and disk usage.

magick -limit map 500MB -limit memory 500MB -limit disk 100MB in.png -scale 10% out.png

The -debug cache option show how ImageMagick is using memory for a magick command.

Install Anaconda Python in Windows PowerShell

On Windows, Miniconda can be installed from the Command Prompt or PowerShell:

winget install --id=Anaconda.Miniconda3 -e

Update conda from Command Prompt / Terminal:

conda update conda

Setup the new shell support (PowerShell, Bash, Command Prompt, etc.) with

conda init

Reopen Terminal to see new conda environment.


If message upon opening PowerShell like:

Documents\WindowsPowerShell\profile.ps1 cannot be loaded because running scripts is disabled on this system. For more information, see about_Execution_Policies at https:/go.microsoft.com/fwlink/?LinkID=135170

Consider ExecutionPolicy like:

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned