my cmake scripts as a submodule
from the top of any project, run:
cp Makefile Makefile.orig
git submodule add https://github.com/derammo/cmake
make -f cmake/setup.make root
make
then edit the top level CMakeLists.txt to add your project name, vendor, and contact info
cmake/setup.make root generates a top-level Makefile that includes cmake/main.make, which provides the following targets. Run them from the project root.
| target | what it does |
|---|---|
all (default) |
same as release |
release |
configure and build <Platform>/Release (e.g. Linux/Release, Darwin/Release) |
debug |
configure and build <Platform>/Debug |
relWithDebInfo |
configure and build <Platform>/RelWithDebInfo |
configure |
configure all build types, without building, to be used for development of cmake files |
package |
build Release, then run CPack (make package) in the Release build dir |
docker |
build Release, then run the docker custom target if the project defines one (non-fatal if missing) |
test |
build Debug, then run every registered test through ctest --output-on-failure (gtest, npm, maven, ... see below) |
test-<label> |
like test, restricted to one provider label, e.g. make test-npm, make test-jest |
clean |
run make clean inside any existing <Platform>/{Release,RelWithDebInfo,Debug} build dir (keeps the dirs themselves) |
squeaky |
delete <Platform>/ and Windows/ entirely, removing all build artifacts |
info |
print the detected platform and the inputs main.make watches for regeneration |
probe |
print just the detected platform |
trace |
re-run cmake with --trace into <Platform>/Debug for debugging CMake logic |
<Platform> is the output of uname -s (Linux, Darwin, etc.), so build trees for multiple platforms can coexist in the same source tree.
Several of the per-platform paths can also be invoked directly:
make Linux/Release/Makefile
make Linux/Debug/Makefile
make Darwin/Debug/Makefile
Windows does not use make — the equivalents live in the cmake\ submodule and are run from the project root:
| command | equivalent POSIX target | what it does |
|---|---|---|
cmake\make.cmd |
make (all configs) |
generate Windows\ build tree via cmake -B Windows -A x64 |
cmake\open.cmd |
— | run cmake\make.cmd then open every generated .sln in Visual Studio |
cmake\test.cmd |
make test |
run ctest --output-on-failure inside the Windows\ build tree |
In particular, there is no make test on Windows — use cmake\test.cmd instead.
All testing goes through CTest. Each kind of test support registers the tests it finds with add_test() and labels them with the provider name, so the generated test target (and make test / cmake\test.cmd) runs everything, and ctest -L <label> or make test-<label> runs one kind. ctest --print-labels in a build directory lists what a project registered.
| provider file | registers | labels |
|---|---|---|
derammo_gtest.cmake |
one test per Google Test case, discovered from each gtest/ target |
gtest |
derammo_npm.cmake |
npm run test per package: standalone packages register themselves, a workspace root registers one test per member |
npm, plus the framework found in devDependencies (vitest, jest, mocha) |
derammo_maven.cmake |
mvn test for each derammo_maven_build() |
maven |
Test output is kept plain for the captured log (no color: --gtest_color=no, NO_COLOR=1 in the environment of npm tests, mvn --batch-mode), and every provider also writes JUnit XML into <Platform>/<Config>/junit/:
| provider | JUnit XML |
|---|---|
| ctest | junit/ctest.xml, the whole run |
| gtest | junit/<test>.xml, one file per test case |
| npm | junit/<test>.xml: the test's environment carries DERAMMO_JUNIT_FILE, which the generated vitest.config.ts turns into a junit reporter; jest packages get JEST_JUNIT_OUTPUT_FILE for the jest-junit reporter in the template; a package with no known framework is assumed to use node --test and gets the junit reporter through NODE_OPTIONS |
| maven | wherever the pom's surefire reportsDirectory points; surefire has no command line override for it, so point it at @CMAKE_BINARY_DIR@/junit/... from pom.xml.in |
The per-test XML comes from properties of the tests themselves, so any ctest invocation produces it; only junit/ctest.xml depends on the --output-junit argument, which make test, the generated test target, and the Visual Studio RUN_TESTS target pass (CMAKE_CTEST_ARGUMENTS), and cmake\test.cmd does not.
To initialize a suitable config for a library/executable/etc, there are make targets to initialize cmake. For example, if you have a subdirectory "foo" that should be built as a library, you can
cd foo
make -f ../cmake/setup.make library
to create a pretty decent default configuration for a library in the current directory.
cmake/setup.make is always run from the directory being initialized, e.g. make -f cmake/setup.make root from the project root or make -f ../cmake/setup.make executable from a subfolder.
| target | run from | initializes |
|---|---|---|
root |
project root containing the cmake folder |
a new project root: Makefile, top-level CMakeLists.txt with add_subdirectory() entries and CPack support, and a .gitignore (merged with any existing one) |
library |
subfolder of the root | a shared library target: CMakeLists.txt plus sources.cmake listing local sources (PUBLIC), include/ headers (INTERFACE), and src/ files (PRIVATE) |
static |
subfolder of the root | a static library target (runs library with DERAMMO_LIBRARY_TYPE=STATIC) |
executable |
subfolder of the root | an executable target: CMakeLists.txt plus sources.cmake listing local sources (PUBLIC) and src/ files (PRIVATE) |
workspaces |
subfolder of the root | an npm workspace root: CMakeLists.txt, _package_template.json, templates/_package_template_version.json, and .gitignore |
typescript |
subfolder of an npm workspace root | an npm package with TypeScript and vitest support: CMakeLists.txt, _package_template.json, tsconfig.json, eslint.config.js, src/index.ts, and test/index.test.ts |
npm |
subfolder of an npm workspace root | a plain npm package: CMakeLists.txt and _package_template.json |
The npm-related targets (workspaces, typescript, npm) only create files that are not already present, so they can be run against an existing folder — except that they refuse to run if a package.json exists, since the build would replace it with a generated file. The remaining rules in setup.make (Makefile, CMakeLists.txt, .gitignore) are file rules used as prerequisites of root, not targets to invoke directly.
Example usage can be found at https://github.com/derammo/cmake_tests/tree/main/examples
For example, a simple library target with globbing (uses all files currently in the tree, instead of a list of source files) is shown here: https://github.com/derammo/cmake_tests/blob/main/examples/autolib/CMakeLists.txt