We have some libraries that are to be consumed by multiple applications, but with different compile definitions or flags. For example, when compiled with app-A, we need -DappA. When compiled with app-B, we need -DappB. In tranditional Makefile, we do it with target specific variables:
app-A: CFAGS+=-DappA
app-A: commonLib
app-B: CFLAGS+=-DappB
app-B: commonLib
With CMake, I expected target specific commands like target_compile_definitions to be transitive to dependencies, so I did this:
add_subdirectory(commonLib) #where there is add_library(commonLib …)
add_executable(app-A …)
target_compile_definitions(app-A PRIVATE appA)
target_link_libraries(app-A commonLib)
But I didn’t see -DappA was used when compiling the commonLib. Did I do anything wrong? Or it is not transitive to dependencies at all? I have quite a few “common” libraries, and quite a few apps, so it’ll be nice if it is transitive.
Unless I missed something transitivity goes the other way around, if A depends on B then public INTERFACE on B will propagate to A.
In your description app-A depends on commonLib and target_compile_definitions(app-A PRIVATE appA)
applies to target app-A so source any file in app-A will be compiled with -DappA.
But why/how would this propagate to the commonLib compilation?
If this was propagated this way and commonLib was used by bothapp-Aandapp-B you’ll get both -DappA and -DappB ?
From my point of view there is 2 options:
either commonLib is a header only lib and the current scheme should work because -DappA will be defined when compiling app-A
or commonLib needs to be compiled twice, once for appA and once for appB.
I’ll compose an example tomorrow.
What make can do is to pass -DappA down to commonLib. For example:
app-A: CFLAGS+=-DappA
app-A: commonLib
In your commonLib’s makefile:
commonLib: x.c y.c
CC …
You’ll see, when x.c is compiled, -DappA is in the compiling command line. Thus, I can choose different feature to compile from the top app’s makefile.
Not sure if this makes sense to you. I’ll get you an example tomorrow.
It makes perfectly sense (I did use makefile a lot some time ago), but I bet that in that case commonLib is not really a “library” since it shall be recompiled for different app. What you describe is a way to bring in a new commonLib-A into A by specifying a set of source file that need to be recompiled for A.
So you need to create your interface library, with appropriate associated source files in it:
Even with GNU Make, I don’t understand how you get the expected behavior. The GNU Make documentation specifies, for target specific variables values:
Be aware that a given prerequisite will only be built once per invocation of make, at most. If the same file is a prerequisite of multiple targets, and each of those targets has a different value for the same target-specific variable, then the first target to be built will cause that prerequisite to be built and the prerequisite will inherit the target-specific value from the first target. It will ignore the target-specific values from any other targets.
@marc.chevrier, let me ellaborate a little bit more. We do compile twice. We have separate makefiles for appA and appB, which include commonLib’s makefile “commonLib.mk”. With GNU make’s target-specific variable feature, the CFLAGS used to compile commonLib can be tuned by its dependant (appA or appB here)