CMake cannot figure out header dependencies if build is out-of-source? - c++

I've been using CMake to manage a separate small c++ project (Unix Makefile based) and decided to convert it to a more organized out-of-source build. However when it's out-of-source (by doing a cmake .. in build/), my headers are no longer dependencies for their source files. If I just cmake from the top-level, everything is fine again.
So I've made a small test version and found the same problem. I'm on an Arch Linux system by the way. Originally, my project was in the /tmp directory (intentionally) and by reading this question: Handling header files dependencies with cmake, I thought this could be the culprit because CMake might be seeing directories as system ones and hence thinking my headers are from system libraries, so I moved it to my home folder. Nothing changed. I then messed around with the paths in my CMakeLists.txt, but it didn't seem to change anything. I also tried replacing everything with absolute paths.
project/CMakeLists.txt:
cmake_minimum_required (VERSION 2.8)
project (MYTEST)
include_directories(${CMAKE_SOURCE_DIR}/include)
file(GLOB SOURCES "${CMAKE_SOURCE_DIR}/src/*.cpp")
add_executable(app ${SOURCES})
project/src/hey.cpp:
#include "hey.h"
int main()
{
std::cout << "Heyyy" << std::endl;
return 0;
}
project/include/hey.h:
#include <iostream>
Now if I make a new directory project/build and cmake .. from that directory then make, the project compiles. However if I change hey.h in any way and try to make again, nothing will recompile. The depend.make file is consistent with this:
# CMAKE generated file: DO NOT EDIT!
# Generated by "Unix Makefiles" Generator, CMake Version 3.15
CMakeFiles/app.dir/src/hey.cpp.o: ../src/hey.cpp
But if I cmake . from the top directory project, everything goes well and the dependencies are all there:
# CMAKE generated file: DO NOT EDIT!
# Generated by "Unix Makefiles" Generator, CMake Version 3.15
CMakeFiles/app.dir/src/hey.cpp.o: src/hey.cpp
CMakeFiles/app.dir/src/hey.cpp.o: include/hey.h
I have found people having similar problems, but most are edge cases and cause just one header not to be included. My actual project doesn't find any header dependencies. /: I could very easily just be using CMake horribly wrong (I'm sorta new to it), but I looked around and everyone seems to do it differently.

If your build directory is a subdirectory of the source directory, then it's not really out-of-source, but a sort of hybrid. The recommended CMake approach is to do proper out-of-source builds where the source and binary directory are totally unrelated. This means they can be siblings or further removed, but neither is a descendant of the other.

Related

CMake generating VS project files in the files with the CMakeLists.txt folders

I'm trying to learn CMake and am struggling to achieve the project layout that I'm used to making with visual studio.
I want to achieve something like the following directory structure,
where the .vcxproj and .sln are generated by CMake
Root
CMakeLists.txt
MySolution.sln
ProjectOne
CMakeLists.txt
ProjectOne.vcxproj
someSourceFile1.h
someSourceFile1.cpp
ProjectTwo
CMakeLists.txt
ProjectTwo.vcxproj
someSourceFile2.h
someSourceFile2.cpp
Binaries
Platform
Debug
ProjectOne.exe
ProjectTwo.dll
Release
ProjectOne.exe
ProjectTwo.dll
All the tutorials I seem to find seem to give an Examples where the structure turns out something like this:
Root
Source
CMakeLists.txt
ProjectOne
CMakeLists.txt
someSourceFile1.h
someSourceFile1.cpp
ProjectTwo
CMakeLists.txt
someSourceFile2.h
someSourceFile2.cpp
Build
MySolution.sln
ProjectTwo.vcxproj
ProjectOne.vcxproj
Platform
Debug
ProjectOne.exe
ProjectTwo.dll
Release
ProjectOne.exe
ProjectTwo.dll
Using commands like
mkdir Build
cd build
CMake ..\Source
CMake --Build .
Notable I have not added ALL_BUILD.vcxproj and ZERO_CHECK.vcxproj that get generated, which I am yet to understand my need for.
Is there just a command I'm missing in the CMakeList.txt to do this?
Is there a reason I shouldn't lay my project out the way I want to?
Doing some more research I have stumbled across this post Visual Studio puts new files into wrong directory
which made me think I could not mix my dev and dist builds with CMake.
Thanks to the helpful comments of fabian that you can actually build the structure I want and am used to doing something like this.
You can make it only use folders for specific builds if you want it for some and not others.
project(MySolution)
cmake_minimum_required(VERSION 3.2)
# Use solution folders if I'm using VS change to whatever your dev platform is
IF(MSVC)
SET_PROPERTY(GLOBAL PROPERTY USE_FOLDERS ON)
ENDIF()
add_subdirectory(MyFolderName)
Having a play with it, your dev build does need to call CMake from the \source folder where a distribution build would need to be called from the \Build directory to separate out the files.
I'm guessing there's ways to use more If() ... Else() ... Endif() to generate this in a specific folder based on build type as well.
Having a look around, I think the easiest way might just be to place another scripting language over the top that just calls the cmake commands from different directories based on build type.
Windows.scriptType
Linux.scriptType
etc...
Unless some kind soul can point me how to do this one in CMake

Binaries missing after successful build?

I have a CMake project that I use to generate a Visual Studio solution, which I then try to compile. For some reason, the library file after compilation is nonexistent. I've searched my entire project folder, and cannot find any library files. Here's my CMake setup:
Project root:
cmake_minimum_required(VERSION 3.22)
project(ShadowContainers)
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
include_directories(include/)
add_subdirectory(library)
...
library subdirectory:
add_library(libShadows shadows.tpp ../include/shadows.hpp)
set_target_properties(libShadows PROPERTIES LINKER_LANGUAGE CXX) # a tpp and an hpp aren't enough to make the system certain it's c++
target_compile_features(libShadows PRIVATE cxx_std_23)
The MSbuild output contains these lines:
Done Building Project "C:\Users\[..]\projects\Shadow Array\library\libShadows.vcxproj" (default targets).
Done Building Project "C:\Users\[..]\projects\Shadow Array\library\libShadows.vcxproj.metaproj" (default targets).
Even if libShadows is the only target in my project, it's nowhere in my project directory.
Has anybody else had this experience? Any help is appreciated. Thanks!
Edit:
To compile the project, I have tried:
My typical process (working directory = the project root):
cmake .
msbuild ShadowContainers.sln
An alternate process (working directory also project root):
mkdir build
cd build
cmake ..
cmake --build .
Both have produced the same result, albeit with VS and CMake files in different places. No library is outputted either way.
I was able to find the issue. CMake (and conventions for that matter) do not see a .tpp as a code file (similarly to how they treat header files). Thus, I was trying to compile a target with no legitimate code files. Template-only libraries are not libraries at all, so I should not be attempting to compile this standalone, and should instead put the .hpp and .tpp as the include in my projects!

CMake output to build directory [duplicate]

Is it possible to specify build directory within CMakeLists file? If yes, how.
My aim is to be able to call "cmake" within top level source directory and have cmake figure out the build directory.
Afaik, with CMake the build directory is always the directory from where you invoke the cmake or ccmake command. So if you want to change the build directory, you have to change directories before running CMake.
To control the location where executables, static and shared libraries are placed once finished, you can modifiy CMAKE_RUNTIME_OUTPUT_DIRECTORY, CMAKE_ARCHIVE_OUTPUT_DIRECTORY, and CMAKE_LIBRARY_OUTPUT_DIRECTORY respectively.
By design, there is not a way to specify that in CMakeLists.txt. It is designed for the user to be able to build the project in whatever directory they want. The typical workflow is:
Check out the project source code.
Go to desired build directory, or the source dir if you plan to do an in-source build.
Run cmake or ccmake to configure the project in that build directory.
Build your project.
All of the directories specified within your CMakeLists.txt should be relative to the ${PROJECT_BINARY_DIR} and ${PROJECT_SOURCE_DIR} variables. In this way, your code becomes buildable across different platforms, which is the goal of CMake.

CMake/Ninja attempting to compile deleted `.cpp` file

I've found that when I delete cpp files from my project using cmake and ninja, I can't easily compile it without first completely deleting my build directory and starting from scratch. CMake and/or Ninja apparently squirrels away a number of references to all the cpp files that it compiles, even deleting the CMake cache before re-running CMake doesn't remove all the references.
Is this a known issue? Is there a solution? I've occasionally just run rm $(grep -R <filename> <builddir>), but that's a terrible kludge.
EDIT: It appears I was mistaken, as I have not been able to duplicate this problem. Manually re-running CMake appears to always generate the correct list of .cpp files, even using GLOB to generate lists of sources.
Turning my comments into an answer
Collecting your source files with file(GLOB ...)
Yes, CMake won't know about new or deleted source files when collecting your source files with the file(GLOB ...) command. This is a known restriction with CMake. I've changed my CMake project(s) to list all source files individually exactly because of this. Out of convenience I'm still collecting my header files with the file(GLOB ...) command.
Quoting from CMake's file() command documentation:
We do not recommend using GLOB to collect a list of source files from
your source tree. If no CMakeLists.txt file changes when a source is
added or removed then the generated build system cannot know when to
ask CMake to regenerate.
Deleting CMakeCache.txt to retrigger Configuration
Just deleting CMakeCache.txt may not be enough to retrigger the CMake configuration. Issue 0014820: warn users about removing only CMakeCache.txt claims you need also to delete all CMakeFiles directories.
From my experience the most reliable way to retrigger the CMake configuration is to touch one of the projects CMakeLists.txt files.
Note: For ninja CMake adds a rebuild_cache target for conveniently running CMake for your project again.
Retrigger after Updates from Source Control
Just one thought: if the deletion of source files happens because they were removed from your source control there maybe a workaround that still allows you to use file(GLOB ...) on your source files.
E.g. if you use GIT you could add the following to your main CMakeLists.txt:
configure_file(${CMAKE_SOURCE_DIR}/.git/index ${PROJECT_BINARY_DIR}/git_index.tmp)
Disadvantage: It would retrigger configuration which each GIT operation (update, commit, ...).
Some References:
run cmake when adding file in eclipse
CMake: Correct way to make an arbitrary file trigger

What does cmake .. do?

I got the Box2D project source and want to compile the testbed portion of it.
The project folder contains folders like: freeglu glui testbed(a demo) helloword(a demo)
Box2D Build CMakeFiles
There are many CMakeLists.txt in all the different folders.
I was thinking that I should cmake all those files so that make files are created in all places required.
I read this (as instructions to do do want I want) :
wget http://box2d.googlecode.com/files/Box2D_v2.2.1.zip
unzip Box2D_v2.2.1.zip
cd Box2D_v2.2.1/Build
cmake ..
make
What does the cmake .. do?
There is no CMakeLists.txt in the build folder.
cmake is a Makefile generator.
When you call cmake [path], you ask it to generate a Makefile in the current directory following instructions given in [path]/CMakeLists.txt
Usually cmake output some messages while it is working, and after it is done without errors, you can type "make" to execute your newly created Makefile.
CMakeLists.txt files can reference other CMakeLists.txt file in sub-directories, so you are usually only interested by the CMakeLists.txt of the top directory, not the other ones.
Using an empty "build" directory is a technique called "out-of-source build", in which all your generated files (.o, executable, Makefile, .anything) are generated in the separate "build" directory and not mixed with source files. If you want to clean all, you can delete all the content of the build directory.
In fact, you can put your "build" directory in any place, as long as you give cmake the correct path of the top CMakeLists.txt. You can even have several build directories. It is very useful if you need several different builds at the same time (with different options, different versions of gcc, etc.)
In old programs, you generate the Makefile too, but using ./configure (this is called auto-tools. You may have encountered that already). cmake is considered a successor of the auto-tools.
cmake .. generates makefiles in the current directory, using ../CMakeLists.txt file as starting point. make command, executed after this, builds the program, using generated makefile(s) as an input. This is convenient to keep a source code and build results in different folders. General syntax is: cmake source-dir (of course, there are a lot of other switches).
Well, .. is shorthand for the parent folder, so it will presumably act upon whatever it finds in Box2D_v2.2.1.