{"id":13732426,"url":"https://github.com/onqtam/ucm","last_synced_at":"2026-01-06T01:47:40.209Z","repository":{"id":73734418,"uuid":"37800164","full_name":"onqtam/ucm","owner":"onqtam","description":"Useful cmake macros that help with: compiler/linker flags, collecting sources, PCHs, Unity builds and other stuff.","archived":false,"fork":false,"pushed_at":"2023-03-13T21:49:21.000Z","size":194,"stargazers_count":210,"open_issues_count":3,"forks_count":34,"subscribers_count":14,"default_branch":"master","last_synced_at":"2025-01-31T07:42:36.490Z","etag":null,"topics":["cmake","compiler-flags","linker-flags","precompiled-headers","unity-build"],"latest_commit_sha":null,"homepage":"","language":"CMake","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/onqtam.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2015-06-21T07:06:01.000Z","updated_at":"2024-12-05T12:31:57.000Z","dependencies_parsed_at":null,"dependency_job_id":"feb50fa7-202b-4adb-9355-12dab183c18e","html_url":"https://github.com/onqtam/ucm","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/onqtam%2Fucm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/onqtam%2Fucm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/onqtam%2Fucm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/onqtam%2Fucm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/onqtam","download_url":"https://codeload.github.com/onqtam/ucm/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245598314,"owners_count":20641884,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cmake","compiler-flags","linker-flags","precompiled-headers","unity-build"],"created_at":"2024-08-03T02:01:56.065Z","updated_at":"2026-01-06T01:47:40.183Z","avatar_url":"https://github.com/onqtam.png","language":"CMake","readme":"ucm - useful cmake macros\r\n-------------------------\r\n\r\nucm is a collection of cmake macros that help with:\r\n\r\n- managing compiler/linker flags\r\n- collecting source files with grouping in IDEs that mimics the filesystem structure\r\n- easy removing source files from already collected ones\r\n- adding a precompiled header for targets\r\n- [unity builds](#unity-builds) of targets\r\n- others... contribution is welcome!\r\n\r\nTested with MSVC/GCC/Clang.\r\n\r\n[cotire](https://github.com/sakra/cotire) is an optional submodule for the [ucm_add_target()](#ucm_add_target) macro either do ```git submodule update --init``` after cloning or include cotire in your cmake files before ucm.\r\n\r\n[![Language](https://img.shields.io/badge/language-CMake-blue.svg)](https://en.wikipedia.org/wiki/CMake)\r\n[![License](http://img.shields.io/badge/license-MIT-blue.svg)](http://opensource.org/licenses/MIT)\r\n[![Linux/OSX Status](https://travis-ci.org/onqtam/ucm.svg?branch=master)](https://travis-ci.org/onqtam/ucm)\r\n[![Windows Status](https://ci.appveyor.com/api/projects/status/m80f32y206l9tb52?svg=true)](https://ci.appveyor.com/project/onqtam/ucm)\r\n\r\nDocumentation\r\n-------------\r\n\r\n##### \u003ca name=\"macros\"\u003e\u003c/a\u003eMacros:\r\n\r\n- [ucm_print_flags](#ucm_print_flags)\r\n- [ucm_add_flags](#ucm_add_flags)\r\n- [ucm_set_flags](#ucm_set_flags)\r\n- [ucm_remove_flags](#ucm_remove_flags)\r\n- [ucm_add_linker_flags](#ucm_add_linker_flags)\r\n- [ucm_set_linker_flags](#ucm_set_linker_flags)\r\n- [ucm_set_runtime](#ucm_set_runtime)\r\n- [ucm_set_xcode_attrib](#ucm_set_xcode_attrib)\r\n- [ucm_add_files](#ucm_add_files)\r\n- [ucm_add_dirs](#ucm_add_dirs)\r\n- [ucm_count_sources](#ucm_count_sources)\r\n- [ucm_include_file_in_sources](#ucm_include_file_in_sources)\r\n- [ucm_dir_list](#ucm_dir_list)\r\n- [ucm_remove_files](#ucm_remove_files)\r\n- [ucm_remove_directories](#ucm_remove_directories)\r\n- [ucm_add_target](#ucm_add_target)\r\n\r\nMacro notation: ```myMacro(NAME \u003cname\u003e [FLAG])``` - ```NAME``` and a name after it are required and FLAG is optional (because in brackets).\r\n\r\n##### \u003ca name=\"ucm_print_flags\"\u003e\u003c/a\u003emacro ```ucm_print_flags()```\r\n\r\nPrints all relevant flags - for example with ```-DCMAKE_BUILD_TYPE=Debug``` given to cmake for makefiles:\r\n\r\n```\r\nCMAKE_C_FLAGS_DEBUG: -g\r\nCMAKE_CXX_FLAGS_DEBUG: -g\r\nCMAKE_C_FLAGS:  --save-temps -std=c++98 -pedantic -m64 -O2 -fvisibility=hidden\r\nCMAKE_CXX_FLAGS:  --save-temps -std=c++98 -pedantic -m64 -O2 -fvisibility=hidden\r\n```\r\n\r\nor for a multi config generator like Visual Studio:\r\n\r\n```\r\nCMAKE_C_FLAGS_DEBUG: /D_DEBUG /MDd /Zi /Ob0 /Od /RTC1\r\nCMAKE_CXX_FLAGS_DEBUG: /D_DEBUG /MDd /Zi /Ob0 /Od /RTC1\r\nCMAKE_C_FLAGS_RELEASE: /MD /O2 /Ob2 /D NDEBUG\r\nCMAKE_CXX_FLAGS_RELEASE: /MD /O2 /Ob2 /D NDEBUG\r\nCMAKE_C_FLAGS:  /DWIN32 /D_WINDOWS /W3 /W4\r\nCMAKE_CXX_FLAGS:  /DWIN32 /D_WINDOWS /W3 /GR /EHsc /W4\r\n```\r\n\r\n##### \u003ca name=\"ucm_add_flags\"\u003e\u003c/a\u003emacro ```ucm_add_flags([C] [CXX] [CONFIG \u003cconfig\u003e] flag1 flag2 flag3...)```\r\n\r\nAppend the flags to a different set depending on it's options - examples:\r\n\r\n```cmake\r\nucm_add_flags(-O3 -Wextra) # will add to CMAKE_C_FLAGS and CMAKE_CXX_FLAGS\r\nucm_add_flags(C -O3) # will add to CMAKE_C_FLAGS\r\nucm_add_flags(CXX -O3) # will add to CMAKE_CXX_FLAGS\r\nucm_add_flags(-O3 -Wall CONFIG Debug) # will add to CMAKE_C_FLAGS_DEBUG and CMAKE_CXX_FLAGS_DEBUG\r\nucm_add_flags(C -Wall CONFIG Debug Release) # will add to CMAKE_C_FLAGS_DEBUG and CMAKE_C_FLAGS_RELEASE\r\n```\r\n\r\n##### \u003ca name=\"ucm_set_flags\"\u003e\u003c/a\u003emacro ```ucm_set_flags([C] [CXX] [CONFIG \u003cconfig\u003e] flag1 flag2 flag3...)```\r\n\r\nRemoves the old and sets the new flags to a different set depending on it's options - examples:\r\n\r\n```cmake\r\nucm_set_flags(CXX) # will clear CMAKE_CXX_FLAGS\r\nucm_set_flags() # will clear both CMAKE_C_FLAGS and CMAKE_CXX_FLAGS\r\nucm_set_flags(CXX -O3) # will set CMAKE_CXX_FLAGS\r\nucm_set_flags(-O3 -Wall CONFIG Debug) # will set CMAKE_C_FLAGS_DEBUG and CMAKE_CXX_FLAGS_DEBUG\r\n```\r\n\r\n##### \u003ca name=\"ucm_remove_flags\"\u003e\u003c/a\u003emacro ```ucm_remove_flags([C] [CXX] [CONFIG \u003cconfig\u003e] flag1 flag2 flag3...)```\r\n\r\nRemoves the flags from a different set depending on it's options - examples:\r\n```cmake\r\nucm_remove_flags(CXX /EHsc /GR) # will remove from CMAKE_CXX_FLAGS\r\nucm_remove_flags(/W3) # will remove from both CMAKE_C_FLAGS and CMAKE_CXX_FLAGS\r\nucm_remove_flags(/RTC1 CONFIG Debug) # will remove from CMAKE_C_FLAGS_DEBUG and CMAKE_CXX_FLAGS_DEBUG\r\n```\r\n\r\n##### \u003ca name=\"ucm_add_linker_flags\"\u003e\u003c/a\u003emacro ```ucm_add_linker_flags([EXE] [MODULE] [SHARED] [STATIC] [CONFIG \u003cconfig\u003e] flag1 flag2 flag3...)```\r\n\r\nAppend the flags to a different set depending on it's options - examples:\r\n\r\n```cmake\r\nucm_add_linker_flags(/NXCOMPAT) # will add to CMAKE_\u003cTYPE\u003e_LINKER_FLAGS (TYPE is all 4 - exe/module/shared/static)\r\nucm_add_linker_flags(EXE /DYNAMICBASE CONFIG Release) # will add to CMAKE_EXE_LINKER_FLAGS_RELEASE only\r\nucm_add_flags(EXE /DYNAMICBASE CONFIG Debug Release) # will add to CMAKE_EXE_LINKER_FLAGS_DEBUG and CMAKE_EXE_LINKER_FLAGS_RELEASE\r\n```\r\n\r\n##### \u003ca name=\"ucm_set_linker_flags\"\u003e\u003c/a\u003emacro ```ucm_set_linker_flags([EXE] [MODULE] [SHARED] [STATIC] [CONFIG \u003cconfig\u003e] flag1 flag2 flag3...)```\r\n\r\nRemoves the old and sets the new flags to a different set depending on it's options - examples:\r\n\r\n```cmake\r\nucm_set_linker_flags(/NXCOMPAT) # will clear all CMAKE_\u003cTYPE\u003e_LINKER_FLAGS\r\nucm_set_linker_flags(EXE /DYNAMICBASE CONFIG Release) # will set CMAKE_EXE_LINKER_FLAGS_RELEASE only\r\n```\r\n\r\n##### \u003ca name=\"ucm_set_runtime\"\u003e\u003c/a\u003emacro ```ucm_set_runtime([STATIC] [DYNAMIC])```\r\n\r\nSets the runtime to static/dynamic - for example with Visual Studio as a generator:\r\n\r\n```cmake\r\nucm_print_flags()\r\nucm_set_runtime(STATIC)\r\nucm_print_flags()\r\n```\r\n\r\nwill result in:\r\n\r\n```\r\nCMAKE_C_FLAGS_DEBUG: /D_DEBUG /MDd /Zi /Ob0 /Od /RTC1\r\nCMAKE_CXX_FLAGS_DEBUG: /D_DEBUG /MDd /Zi /Ob0 /Od /RTC1\r\nCMAKE_C_FLAGS_RELEASE: /MD /O2 /Ob2 /D NDEBUG\r\nCMAKE_CXX_FLAGS_RELEASE: /MD /O2 /Ob2 /D NDEBUG\r\nCMAKE_C_FLAGS:  /DWIN32 /D_WINDOWS /W3 /W4\r\nCMAKE_CXX_FLAGS:  /DWIN32 /D_WINDOWS /W3 /GR /EHsc /W4\r\n\r\nCMAKE_C_FLAGS_DEBUG: /D_DEBUG /MTd /Zi /Ob0 /Od /RTC1\r\nCMAKE_CXX_FLAGS_DEBUG: /D_DEBUG /MTd /Zi /Ob0 /Od /RTC1\r\nCMAKE_C_FLAGS_RELEASE: /MT /O2 /Ob2 /D NDEBUG\r\nCMAKE_CXX_FLAGS_RELEASE: /MT /O2 /Ob2 /D NDEBUG\r\nCMAKE_C_FLAGS:  /DWIN32 /D_WINDOWS /W3 /W4\r\nCMAKE_CXX_FLAGS:  /DWIN32 /D_WINDOWS /W3 /GR /EHsc /W4\r\n```\r\n##### \u003ca name=\"ucm_set_xcode_attrib\"\u003e\u003c/a\u003emacro ```ucm_set_xcode_attrib(name value [CLEAR] [CONFIG \u003cconfig\u003e])```\r\n\r\nSets an Xcode attribute and optionally per-configuration:\r\n\r\n```cmake\r\nucm_set_xcode_attrib(DEBUG_INFORMATION_FORMAT \"dwarf-with-dsym\")\r\nucm_set_xcode_attrib(DEAD_CODE_STRIPPING \"YES\" CONFIG Debug Release)\r\n```\r\n\r\nwill result in:\r\n\r\n```\r\nCMAKE_XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT: \"dwarf-with-dsym\"\r\nCMAKE_XCODE_ATTRIBUTE_DEAD_CODE_STRIPPING[variant=Debug]: \"YES\"\r\nCMAKE_XCODE_ATTRIBUTE_DEAD_CODE_STRIPPING[variant=Release]: \"YES\"\r\n```\r\n\r\n##### \u003ca name=\"ucm_add_files\"\u003e\u003c/a\u003emacro ```ucm_add_files(src1 src2 scr3... TO \u003csources\u003e [FILTER_POP \u003cnum\u003e])```\r\n\r\nAdds the sources to the sources variable and sets up filters for the solution explorer of Visual Studio (probably for XCode/CodeBlocks too).\r\n\r\nThe filters will mimic the filesystem - if we have given ```dir1/test/a.cpp``` we would have by default ```dir1/test``` as nested filters in the solution explorer. This can be controlled with ```FILTER_POP``` - 1 would result in only ```test``` as a filter and 2 would result in no filter for ```a.cpp``` - see [ucm_add_dirs](#ucm_add_dirs) for a visual example.\r\n\r\n```CMake\r\nucm_add_files(\"dir/some1.cpp\" \"dir/some1.h\" TO sources)\r\n```\r\n\r\n##### \u003ca name=\"ucm_add_dirs\"\u003e\u003c/a\u003emacro ```ucm_add_dirs(dir1 dir2 dir3... TO \u003csources\u003e [RECURSIVE] [FILTER_POP \u003cnum\u003e] [ADDITIONAL_EXT ext1 ext2 ...])```\r\n\r\nAdds all sources (sources and headers with all valid c/c++ extensions) from the directories given.\r\n\r\nCan be recursive with the ```RECURSIVE``` flag.\r\n\r\nLike ```ucm_add_files()``` filters for the solution explorer of IDEs can be controlled with ```FILTER_POP``` - example:\r\n\r\n| CMake code                                       | result                           |\r\n|--------------------------------------------------|----------------------------------|\r\n| ```ucm_add_dirs(util TO sources)```              | ![0](test/doc_data/filter_0.png) |\r\n| ```ucm_add_dirs(util TO sources FILTER_POP 1)``` | ![1](test/doc_data/filter_1.png) |\r\n\r\nAdditional extensions for collection can be added with the ```ADDITIONAL_EXT``` list.\r\n\r\n##### \u003ca name=\"ucm_count_sources\"\u003e\u003c/a\u003emacro ```ucm_count_sources(src1 src2 src3... RESULT \u003cresult\u003e)```\r\n\r\nGiven a list of sources - returns the number of source files (no headers - only valid source extensions) in the result.\r\n\r\n```\r\nset(sources \"a.cpp;b.cpp;h.hpp\")\r\nucm_count_sources(${sources} c.cpp d.cpp RESULT res) # would return 4 in res\r\n```\r\n\r\n##### \u003ca name=\"ucm_include_file_in_sources\"\u003e\u003c/a\u003emacro ```ucm_include_file_in_sources(src1 src2 src3... HEADER \u003cheader\u003e)```\r\n\r\nIncludes the header in the source file with a compile flag (without modifying the file) either with ```-include \"hdr.h\"``` or with ```/FI\"hdr.h\"``` depending on the compiler.\r\n\r\n```CMake\r\nucm_include_file_in_sources(c.cc a.cc b.cc HEADER \"common.h\")\r\n```\r\n\r\n##### \u003ca name=\"ucm_dir_list\"\u003e\u003c/a\u003emacro ```ucm_dir_list(\u003cthedir\u003e \u003cresult\u003e)```\r\n\r\nReturns a list of subdirectories for a given directory.\r\n\r\n```CMake\r\nucm_dir_list(\"the/dir\" result)\r\n```\r\n\r\n##### \u003ca name=\"ucm_remove_files\"\u003e\u003c/a\u003emacro ```ucm_remove_files(src1 src2 src3... FROM \u003csources\u003e)```\r\n\r\nRemoves the given source files from the sources list - example:\r\n\r\n```CMake\r\nucm_add_dirs(utils REC TO sources)\r\nucm_remove_files(utils/deprecated.h FROM sources)\r\n```\r\n\r\n##### \u003ca name=\"ucm_remove_directories\"\u003e\u003c/a\u003emacro ```ucm_remove_directories(dir1 dir2 dir3... FROM \u003csources\u003e [MATCHES pttrn1 pttrn2])```\r\n\r\nRemoves all source files from the given directories from the sources list (recursively) - example:\r\n\r\n```CMake\r\nucm_add_dirs(utils REC TO sources)\r\n# and then remove only the ones we don't want\r\nucm_remove_directories(utils/deprecated utils/experimental FROM sources)\r\n```\r\n\r\nPatterns can also be given like this:\r\n\r\n```CMake\r\nucm_remove_directories(utils FROM sources MATCHES win32)\r\n```\r\n\r\n##### \u003ca name=\"ucm_add_target\"\u003e\u003c/a\u003emacro ```ucm_add_target(NAME \u003cname\u003e TYPE \u003cEXECUTABLE|STATIC|SHARED|MODULE\u003e SOURCES src1 src2 src3... [PCH_FILE \u003cpch\u003e] [UNITY [CPP_PER_UNITY \u003cnum\u003e] [UNITY_EXCLUDED excl_src1 excl_src2 ...]])```\r\n\r\nA wrapper of ```add_library()``` and ```add_executable()``` calls. Uses [cotire](https://github.com/sakra/cotire) for platform/compiler independent usage of precompiled headers and/or making a unity build of the target.\r\n\r\nFor information about unity builds in general go to the [bottom](#unity-builds).\r\n\r\n```CMake\r\nucm_add_target(NAME example TYPE EXECUTABLE SOURCES \"${sources}\" PCH_FILE precompiled.h)\r\n```\r\n\r\nThe example above shows how to add a target with a precompiled header.\r\n\r\n```CMake\r\nucm_add_target(NAME example TYPE EXECUTABLE SOURCES \"${sources}\" UNITY CPP_PER_UNITY 20 UNITY_EXCLUDED \"separate/some2.cpp\")\r\n```\r\n\r\nWhen the ```UCM_UNITY_BUILD``` ucm option is set to ```ON``` (```OFF``` by default) a target registered like in the example above will actually result in 2 targets added - the unity target with ```example``` as a name (included in the build by default) and the original target with ```example_ORIGINAL``` as a name (excluded from the build by default). This allows the user to browse and modify the sources in the original target properly within the IDE. Also ```separate/some2.cpp``` will be built normally and will not be included in the unity sources.\r\n\r\nWhen new sources are added to the original target the unity target will be updated accordingly by cotire.\r\n\r\nThe order in which sources are given to ```SOURCES``` is the order in which they will appear in the unity files so you can combat compilation issues by changing the order of the source files.\r\n\r\nTargets can be excluded from unity builds by adding them in the ```UCM_UNITY_BUILD_EXCLUDE_TARGETS``` list when invoking cmake (handy if a target becomes problematic in a unity build or if you want to iterate fast on a particular target and want to compile it's sources separately).\r\n\r\nMixed language targets (C/C++) are handled properly - separate unity files are generated for the different languages.\r\n\r\nThe macro will self-diagnose the target and if it has more than 1 source file and has not been registered with the UNITY flag a developer warning will be printed that the target may benefit from a unity build.\r\n\r\nCPP_PER_UNITY - to explicitly say how many source files should go into a unity source (default is 100). Another option is to pass not a number but ```-jX``` after ```CPP_PER_UNITY``` and that would mean dividing the sources into X unity sources.\r\n\r\nUNITY_EXCLUDED - list of files from the target that should be excluded from unify-ing (will be used normally by themselves - can be used to fix compilation errors).\r\n\r\nUnity examples - given 100 .cpp files in the target:\r\n\r\n- ```CPP_PER_UNITY 5``` would mean 20 .cxx unity files including 5 of the original .cpp files each\r\n- ```CPP_PER_UNITY 10``` would mean 10 .cxx unity files including 10 of the original .cpp files each\r\n- ```CPP_PER_UNITY -j8``` would mean 8 .cxx unity files dividing the original 100 among them\r\n\r\nHow a unity target looks in the IDE:\r\n\r\n![1](test/doc_data/unity.png)\r\n\r\nUnity builds\r\n------------\r\n\r\nFor all the pros and cons checkout my [blog post](http://onqtam.github.io/programming/2018-07-07-unity-builds/).\r\n","funding_links":[],"categories":["Tools","Utility Scripts"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fonqtam%2Fucm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fonqtam%2Fucm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fonqtam%2Fucm/lists"}