0

I have a CMake project and I would like to exclude the generated project files from version control.

From my understanding there is no way to force CMake to use a certain build directory. The user can specify any directory they want and therefore I cant exclude it in my .gitignore. Usually the user would place it in a directory called build inside the source directory and I would put that in .gitignore. But I had the crazy idea to call it meta_build, which led me to this problem. Also, an inexperienced user might do an in-source build. It's just a matter of time until someone accidentally checks in the generated project files.

Any ideas or workarounds for this matter are much appreciated.

starball
  • 20,030
  • 7
  • 43
  • 238
  • Every CMake build directory contains e.g. a file `CMakeCache.txt`. So you could just tell the git to not commit any directory which has such file. Unfortunately, I don't know how to do that in git. I don't get your problem around `build` and `meta_build` directories, but forbidding *in-source builds* could be easily done in the CMake project itself: https://stackoverflow.com/questions/1208681/with-cmake-how-would-you-disable-in-source-builds. – Tsyvarev Jun 13 '23 at 12:46
  • You can always do `if (NOT "${CMAKE_SOURCE_DIR}/build" STREQUAL "${CMAKE_BINARY_DIR}") message(FATAL_ERROR "You shall not pass!!!") endif()` optionally just with a non fatal warning. Other than that you can probably just encourage the user to use the desired directory for the build, by providing a script for the cmake configuration/build and/or a `CMakePresets.json`. One additional trick that could work assuming noone uses a build directory matching one of your source directories would be to simply generate a `.gitignore` file in the binary dir. – fabian Jun 13 '23 at 16:22
  • @fabian Thanks, the `if` block mostly solves my problem. However the `**/CMakeFiles` and `**/CMakeCache.txt` are still created by the CMake run, so I added them to .gitignore. I also tried excluding all subdirectories containing these files, like @Tsyvarev suggested, but it seems it is not possible in git. @fabian, if you post an anwser I can accept it as solved. – KnuppenSasper Jun 15 '23 at 07:52

2 Answers2

1

There are a few options to handle this:

Educate your users. Document clearly that generated build files should not be committed, and that an out-of-source build is recommended. This is not a technical solution but can be effective.

Use a pre-commit hook to check for generated files. You can write a script to run on pre-commit to check for common build file names and warn the user. They would still have to manually remove the files, but it alerts them to the issue.

Use CMake's EXCLUDE_FROM_ALL target property. You can mark the target that generates the build files as EXCLUDE_FROM_ALL, meaning it will not be built by default. Users would have to explicitly build that target to generate the build files. This makes it less likely they will be accidentally committed.

Generate the build files in a subdirectory. Have your top-level CMakeLists.txt generate the build files in a build_files subdirectory. Then you can add build_files/ to .gitignore. Users would have to run CMake from build_files for an in-source build, making it clear that directory should be ignored.

Consider not generating project files at all. If you build and distribute a binary library, you could provide just a CMakeLists.txt for people to link against the library. No project files are generated that could be accidentally committed. Of course, this doesn't work if you need project files to actually build your project!

Web Server
  • 21
  • 3
  • Educating the users is a valid point but no solution. Using pre-commit seems not viable to me since I dont even know what kind of project files will be generated on different platforms. It is just one target which always has to be built. So using EXCLUDE_FROM_ALL is not an option. Gnerating the project files in a subdirectory is exactly what I want. But as I said I understand that CMake does not provide an option to do that. Not generating project files is not an option because I need them to build the project. – KnuppenSasper Jun 13 '23 at 09:57
0

I assume this is an issue for you because those other users are collaborating on the project and also potentially pushing to a shared remote. In that case, you have options:

  • Set a convention for only building to a subdirectory with a common name. For example, The PitchFork Layout's build/. I personally put all my builds in a out/build/<build_name> directory. Then you can just gitignore that one directory.

  • Allow your collaborating users to put build anywhere they want in their local clone, and in order to avoid arbitrary explosion of the gitignore, tell them to use their $XDG_CONFIG_HOME/git/ignore, or the local clone's $GIT_DIR/info/exclude (docs).

  • You can hint users to use a particular build directory name(s) using presets: https://cmake.org/cmake/help/latest/manual/cmake-presets.7.html (see the binaryDir property for configuration presets).

  • Technically you can write the gitignore on a filename basis independent of where the build directory is (Ex. listing out individually *.exe, etc.), but that sounds like a real pain in the butt- especially given that different buildsystem generators will have different build artifacts and specific buildsystem configuration files, and that different platforms have different prefixes and suffixes for target output file names (see for example CMAKE_EXECUTABLE_SUFFIX).

starball
  • 20,030
  • 7
  • 43
  • 238