When macOS, Xcode, or Command Line Tools upgrades, build directories (including for CMake-based projects) often need to be refreshed.
If the user has set custom environment variables concerning Xcode, they may need to be updated as well.
Here are some important environment variables and CMake variables to check if problems occur after upgrading.
For a simple CMake project on macOS, CMakeCache.txt might include:
If Homebrew GCC breaks after upgrading Xcode or Command Line Tools, try specifying an older SDK.
For example, if g++-14 main.cpp -v shows a different (older) SDK than CMake and it works, try specifying that SDK in environment variable SDKROOT.
Note that the SDK version corresponds to macOS version, not the XCode version.
For example, if the latest SDK is MacOSX14.4.sdk, try using MacOSX13.3.sdk in “~/gcc.sh”:
and then source ~/gcc.sh before running cmake with a fresh build directory.
If a CMake build step fails, try copy-pasting the command and removing the -isysroot portion of the command.
This is a clear clue the older SDK is (at least temporarily) needed till Homebrew updates its GCC formula.
GCC will tell where included files are coming from by adding the gcc -H flag.
This tells what to specify for environment variable SDKROOT.
The Zoom app offers an option to play audio tones when muting or unmuting the microphone, providing enhanced accessibility for users with visual impairments or other disabilities.
This setting is OFF by default and can be enabled from the Zoom Workplace app under Settings then Audio.
When enabled, users will hear a tone, audible only to them, indicating the mute or unmute action.
When running CMake standalone scripts like
cmake -P script.cmake
this is the SCRIPTCMake role.
Not all
CMake information variables
are set in SCRIPT role, in particular, the CMAKE_HOST* and CMAKE_SYSTEM* variables are not set as they are in PROJECT role.
This is a workaround for cmake -P SCRIPT role to get the CMAKE_HOST_* variables.
It uses undocumented CMake-internal scripts, but they’ve been present since 2012 and may be unlikely to change.
message(STATUS"CMake ${CMAKE_VERSION}")get_property(cmake_roleGLOBALPROPERTYCMAKE_ROLE)if(cmake_roleSTREQUAL"SCRIPT") set(CMAKE_PLATFORM_INFO_DIR${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY})# define CMAKE_HOST*, CMAKE_SYSTEM*, etc.
include(${CMAKE_ROOT}/Modules/CMakeDetermineSystem.cmake)# set booleans like CYGWIN
include(${CMAKE_ROOT}/Modules/CMakeSystemSpecificInitialize.cmake)# needed by Modules/Platform/*.cmake
include(${CMAKE_ROOT}/Modules/CMakeSystemSpecificInformation.cmake)# define CMAKE_SHARED_LIBRARY_SUFFIX, CMAKE_SHARED_LIBRARY_PREFIX, etc.
include(${CMAKE_ROOT}/Modules/Platform/${CMAKE_SYSTEM_NAME}.cmake)endif()message(STATUS"CMAKE_SYSTEM: ${CMAKE_SYSTEM}")message(STATUS"CMAKE_SYSTEM_NAME: ${CMAKE_SYSTEM_NAME}")message(STATUS"CMAKE_SYSTEM_VERSION: ${CMAKE_SYSTEM_VERSION}")message(STATUS"CMAKE_SYSTEM_PROCESSOR: ${CMAKE_SYSTEM_PROCESSOR}")message(STATUS"CMAKE_HOST_SYSTEM: ${CMAKE_HOST_SYSTEM}")message(STATUS"CMAKE_HOST_SYSTEM_NAME: ${CMAKE_HOST_SYSTEM_NAME}")message(STATUS"CMAKE_HOST_SYSTEM_VERSION: ${CMAKE_HOST_SYSTEM_VERSION}")message(STATUS"CMAKE_HOST_SYSTEM_PROCESSOR: ${CMAKE_HOST_SYSTEM_PROCESSOR}")message(STATUS"CMAKE_SHARED_LIBRARY_SUFFIX: ${CMAKE_SHARED_LIBRARY_SUFFIX}")message(STATUS"CMAKE_SHARED_LIBRARY_PREFIX: ${CMAKE_SHARED_LIBRARY_PREFIX}")message(STATUS"CMAKE_STATIC_LIBRARY_SUFFIX: ${CMAKE_STATIC_LIBRARY_SUFFIX}")message(STATUS"CMAKE_STATIC_LIBRARY_PREFIX: ${CMAKE_STATIC_LIBRARY_PREFIX}")
Meson can set a default C++ (or C) langauge standard level with fallback to older versions.
This allows recent compilers to support the full functionality of the project code, while falling back for older compilers.
get_option('cpp_std') can be used for logic within meson.build if desired.
We usually avoid the WSL default of putting the full Windows PATH into WSL.
Particularly when using a build system like CMake, there will be Windows libraries that WSL-based CMake thinks it can use that it actually can’t.
Fix by editing Windows file
$HOME/.wslconfig
inside the WSL distro:
When reading the documentation for a C library function, you may see a note that the function requires a feature test macro to be defined. This is common for functions that are not part of the C standard library but are part of POSIX or another standard. The feature test macro tells the compiler to include the necessary headers and definitions for the function.
Often the
_DEFAULT_SOURCE
macro is sufficient.
Try doing in C BEFORE including the header file that defines the function:
The default CMake build generator is operating system dependent.
In general many projects can benefit from increased build speed and especially rebuild speed of Ninja.
Switch the default build generator on any platform by setting environment variable
CMAKE_GENERATOR.
Add the location of the Ninja executable to environment variable $PATH or
CMAKE_PROGRAM_PATH.
Note that Ninja work-alikes like Samurai “samu” might get installed by default by some package managers.
These work-alikes might not have a new-enough Ninja API equivalent, so in those cases install the actual Ninja program.
If using
Conan Package Manager,
tell Conan to use Ninja by setting environment variable
The C++
STL <random> header
may not be implemented correctly by some C++ compiler / CPU arch platforms.
If a function using <random> is not essential to the program, avoid build errors by checking that <random> is working at configure time.
This example checks that <random> is working with CMake.
include(CheckSourceCompiles)check_source_compiles(CXX"#include <random>
int main(){
std::mt19937 mt_rand(0);
return 0;
}"HAVE_MERSENNE_TWISTER)add_executable(mainmain.cpp)target_compile_definitions(mainPRIVATE$<$<BOOL:${HAVE_MERSENNE_TWISTER}>:HAVE_MERSENNE_TWISTER>)
The “main.cpp” can have #ifdef HAVE_MERSENNE_TWISTER to conditionally compile code that uses <random>.
This allows the rest of the program that doesn’t use this function to work without <random> or to fallback to a simpler RNG if suitable.
For VM server images in particular, the main display of the VM may never activate. The UTM message is like:
display output is not active
This is solved by powering off the VM, and adding a Serial Device under the UTM VM settings.
Rebooting will automatically popup a separate windows for the Serial terminal, where boot messages and login can be accomplished.
Often the main display window will then start working.
Microcontrollers generally use a different CPU architecture than the developer’s laptop.
This implies a
cross compiler
is needed to build code for the microcontroller on the laptop.
It’s straightforward to install the Raspberry Pi Pico ARM C / C++ cross-compiler on macOS, Windows, and Linux.
Please follow the section relevant to the laptop operating system.
About 2..5 gigabytes of hard drive space is required by the Raspberry Pi Pico SDK and associated tools.
Git, CMake and a cross compiler are used by almost all full projects as well.
This script will install the cross-compiler and other tools needed for the Raspberry Pi Pico SDK, or follow the manual process below.
#!/usr/bin/env bash
set -e
# determine OS and archcase"$OSTYPE" in
linux*)sudo apt update
sudo apt install git cmake g++ gcc-arm-none-eabi libnewlib-arm-none-eabi libstdc++-arm-none-eabi-newlib;;
darwin*)brew install git cmake
brew install --cask gcc-arm-embedded;;
*)echo "$OSTYPE not supported"exit 1esac
The cross-compiler executables have a prefix “arm-none-eabi-” that are linked into $(brew --prefix)/bin for easy use from the command line.
It’s likely the macOS laptop has an Apple Silicon CPU.
If so, it’s necessary to
enable Rosetta.
Rosetta enables most x86 apps on Apple Silicon at nearly full performance.
Note: if on macOS you get a build error like:
arm-none-eabi-gcc: fatal error: cannot read spec file ’nosys.specs’: No such file or directory
and you’ve installed the GCC cross-compiler via:
brew install --cask gcc-arm-embedded
Then something is wrong with the cross-compiler setup.
Windows Subsystem for Linux (WSL) is useful for many projects including the Raspberry Pi Pico SDK.
WSL can be the easiest way to work with non-Windows projects on Windows.
The Ubuntu WSL process takes about 10 minutes depending on download speed.
WSL can be installed via the
Microsoft Store Ubuntu app.
If the Microsoft Store isn’t available on the computer, it is also possible to install Ubuntu WSL manually.
WSL can access
the native Windows filesystem.
WSL sees the native Windows filesystem “C:” in WSL via “/mnt/c”.
Use the native Windows drive under “/mnt/c/pico” from WSL.
Then use Windows File Explorer in path “C:/pico” to drag and drop .uf2 file to Pico.
The cross-compiler install on WSL Ubuntu is just like plain Linux in the section above.
To make switching between Windows and WSL easier, optionally use
Windows Terminal.