--- cmake-generate-sources/sources/my-lib/CMakeLists.txt
+++ cmake-generate-sources/sources/my-lib/CMakeLists.txt
@@ -13,7 +13,7 @@
# -------------------------------------------------------------------------------
# Generate test sources.
# -------------------------------------------------------------------------------
-set(VERSION 0)
+set(VERSION 2)
if(${VERSION} EQUAL 0)
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
@@ -131,9 +131,8 @@
elseif(${VERSION} EQUAL 2)
- # This works for some reason when configuring!?! But not when building.
- set(TARGET_SOURCES_HEADER_FILE "test-source-${VERSION}.h")
- set(TARGET_SOURCES_IMPLEMENTATION_FILE "test-source-${VERSION}.cpp")
+ set(TARGET_SOURCES_HEADER_FILE "${GENERATED_HEADER}")
+ set(TARGET_SOURCES_IMPLEMENTATION_FILE "${GENERATED_IMPLEMENTATION}")
endif()
message("INPUT_HEADER_FILE is: ${INPUT_HEADER_FILE}")
What this does is:
You give version 2 the correct file-paths to the generated sources and
in my-app/CMakeLists.txt
you are retrieving the public source files (aka headers) from your my-lib
library and set their GENERATED
property in the current scope. This prevents add_executable
from complaining that the headers cannot be found while cmaking.
Setting the GENERATED
property in that directory might be obsolete if the above mentioned merge-request lands in CMake 3.20. However, CMake 3.20 will still need some months before it is released.
I hope that was understandable and helpful.
Deniz
I think I am actually using 4 spaces as indentation, which seems to be the default in the VisualStudioCode IDE. Also I enabled autoformatting on save, so I guess I am good with the settings?! I do not know why your editor is showing you a messed up format…
I probably didn’t do that, because I never solved the steps earlier. Eventually I would have fixed that.
I absolutely do want the HEADER to be public. But yes, the implementation can be private. I do not understand why both of you think this is not needed?? How else would my-app
be able to call the functions defined in that header or use the WORLD
definition (#define WORLD "World"
)?
That is essentially the solution I found a few minutes ago as well.
Find a full working example VERSION 4
in the attached project.
cmake-generate-sources.zip (11.4 KB)
They don’t need to be public because the target-level dependency of my-app to my-lib assures that they are created before being used there.
What issue are you trying to solve when making them PUBLIC?
Ahhhh… Ok, now I get it… You guys are correct, I can just add all generated sources as PRIVATE
, I tried it out in my sample project.
I thought, that the #include
of the header file in the MyApp.cpp
file:
#if __has_include("my/namespace/my-header-file-4.h")
#include "my/namespace/my-header-file-4.h"
#endif
would not work, if the source was not declared as PUBLIC
, but it does work, since in the my-lib
target I am adding the include directory as PUBLIC
target_include_directories(${TARGET_NAME} PUBLIC "${CMAKE_CURRENT_BINARY_DIR}/generated")
meaning, it also ’ propagates’ to the my-app
target. If I change it to PRIVATE
I get
… was not declared in this scope
errors, when trying to build the my-app
target
But now I am confused… Why would I ever need to add sources as PUBLIC
? I guess I need to read up on that…
Thanks to both of you for your effort and the time you invest in helping!
I think I am actually using 4 spaces as indentation, which seems to be the default in the VisualStudioCode IDE. Also I enabled autoformatting on save, so I guess I am good with the settings?! I do not know why your editor is showing you a messed up format…
You probably set the tab width to 4 spaces. However, you are still using tabs and those are not automatically replaced by 4 spaces. My editor of choice shows tabs with a width of 8 spaces. That’s why it is messed up.
I absolutely do want the HEADER to be public. But yes, the implementation can be private. I do not understand why both of you think this is not needed?? How else would my-app
be able to call the functions defined in that header or use the WORLD
definition ( #define WORLD "World"
)?
Because with target_link_libraries(my-app Private my-lib)
you are saying to link against the library that is created by target my-lib
. And that library already has the compiled source-file included.
If you put the *.cpp
file in INTERFACE_SOURCES
of my-lib
(as you are insisting to do), that source file will be compiled twice, for my-lib
and for my-app
.
The one compiled for my-lib
will go into the created library, the one compiled for my-app
will go into the executable created my my-app
. However, the library of my-lib
will also get linked into that same executable, so your compiled source file will be linked twice into that executable. And the linker will not like that.
But now I am confused… Why would I ever need to add sources as PUBLIC
? I guess I need to read up on that…
Thanks to both of you for your effort and the time you invest in helping!
In general, you should never need to use target_sources
with keywords PUBLIC
or INTERFACE
for *.cpp
files (aka source files).
*.h
files (aka header files) you never need to provide via target_sources
in order to successfully compile the target. (However, you should give it the correct include-search path using target_include_directories
.)
It can be beneficial to still add the headers to target_sources
because some IDEs can then show these or you want to set some properties on these files from some other directory (like I did in my above solution).
Adding the *.cpp
files with PUBLIC
or INTERFACE
to target_sources
is only useful in special situations. But for the normal situation (which you have here) that is even plain wrong.
Excellent. I will go through my project, because until now I always added the header files as PUBLIC
. I will switch that to PRIVATE
or completely remove the keyword. I guess default would be PRIVATE
, right?! I am going to find that out…
I will probably still add the headers (as PRIVATE
), since my colleagues are using other IDEs, e.g. Visual Studio and Eclipse CDT.
Thanks again for the information!
You can leave the headers with the PUBLIC
keyword as is. No need to change, it (currently) does no harm. (I do not know if this might change in the future but I doubt it.)
Besides, I am not sure if PRIVATE
sources are enough to please IDEs or if they must be using INTERFACE
or PUBLIC
.
Just make sure to properly use target_include_directories
so that other targets, that depend on such targets know where to look for the headers they want to #include
.
Omitting the keyword in target_sources
will not work.
I think I will still get some benefits when adding all sources as PRIVATE
. My CMAKE code will probably get easier to read. Also I am currently keeping my .CPP and .H files separately in a ‘private’ and ‘include’ folder respectively. I will have a closer look and think about it or just try out some things.
I will mark your long reply as the solution, even if @hsattler was already going in the right direction in the first reply. I just didn’t yet understand how all of this fitted together and if I actually had needed them to be public, then marking them as GENERATED
within the my-app
directory would have been the solution.