Pass target file name as compile definition in cmake - cmake

I have CMakeLists.txt with many targets and the targets have configuration-specific suffixes defined. Additionally I want to know the name of the executable inside the program.
Under MSVC++ I do this by defining
add_definitions("-DTARGET_FILE_NAME=\"$(TargetFileName)\"")
But this does not work in other generators. Now that CMake got generator expressions, is there a way that would work with any generator?
I tried something like
add_definitions(-DTARGET_FILE_NAME=$<TARGET_FILE_NAME:$<TARGET_PROPERTY:NAME>>)
but even
add_definitions(-DTARGET_FILE_NAME=$<TARGET_PROPERTY:NAME>)
just places the unescaped $<TARGET_PROPERTY:NAME> in the buildfile. I also tried with just$`, but no luck either.
Note that the compile build command does not know the name of the linker output in many build files, so there does not seem to be any generator-specific hack for some of them either.

compile_definitions does not support generator expressions. Use target_compile_definitions, which does:
target_compile_definitions(somelib PRIVATE NAME=$<TARGET_FILE_NAME:somelib>)
http://www.cmake.org/cmake/help/v3.1/command/target_compile_definitions.html

Related

Do something for all targets

What is the best way to do additional stuff for all (binary) targets?
Examples:
I want to check that each library name follows a pattern.
I want to sign each executable.
I dont what the C/C++ developers to use nonstandard commands (like add_library2). I want them to use and learn the official CMake functions, but have them do additonal, project specific, stuff.
The built-in CMake functions add_library and add_executable can be overidden by defining CMake functions of the same name. E.g., to automatically sign all added executables add the following code:
function (add_executable _name)
_add_executable(${ARGV})
if (TARGET ${_name})
add_custom_command(TARGET ${_name} POST_BUILD
COMMAND sign_executable $<TARGET_FILE:${_name}>)
endif()
endfunction()
The original built-in add_executable can be invoked by prefixing it with an underscore character. The same pattern can be applied to add_library to check the name of the library.
You can overwrite any CMake command/function to extend its functionality, but please
Call Things by their Names
I strongly advocate to call the things by their names and not doing things implicitly. It will be easier for everybody using/maintaining/debugging your CMake based project.
If you want to sign your executable - and that's probably even platform specific - you create a function like add_post_build_step_sign_executable() which would add the appropriate post build steps:
add_executable(MyExe main.cpp)
if (WIN32)
add_post_build_step_sign_executable(MyExe)
endif()
And if you have to repeat yourself too often put that code snippet into a function like my_project_add_signed_executable() itself. It could still have the same parameter syntax as CMake's add_executable() command.
Runtime Checks vs. Static Code Analysis
Regarding library naming checks, I see this more like checking against your project's CMake script coding styles and would not use runtime checks for this.
For example you could use something like cmake-lint or your own external script to check for conformity.
References
How to frame the concept behind CMake?
cmake: get add_library() names
How to ensure consistent coding style for CMakeLists.txt and FindXXX.cmake

Get build command or all compiler flags that will be used to build a target

Is there a sensible way to get a CMake variable containing the build command or all the compiler flags that CMake will associate with a target?
It doesn't seem practical to try to gather and maintain a list of all properties that could add flags. Besides, CMake must have this info somewhere, since it has to eventually generate a build system.
From the CMake docs it looks like this feature once existed and was provided by calling build_command() but this was replaced:
Note In CMake versions prior to 3.0 this command returned a command
line that directly invokes the native build tool for the current
generator.
Is there a new command that gives the old behavior of build_command()?
Is there a sensible way to get a CMake variable containing the build command or all the compiler flags that CMake will associate with a target?
The answer is no (CMake 3.23 is latest at time of writing), not during the CMake configure step.
In general, such a thing is ill-defined, which is likely why it was removed from CMake and will likely not be re-added. The complications arising from generator expressions, multi-config generators, generators that don't construct command lines (like VS/msbuild), source-file-specific properties, and the simple fact that after the command is called, relevant state might change, all make such efforts quixotic.
Honestly, this is such an odd thing to want at configure time, I wonder if this isn't an XY problem. It's unlikely that one target depends on another in such a way that the entire eventual command line is needed (rather than a particular property) to create it.
I know this is many years later now, but what were you trying to do?
CMake provides many ways post-generation to get information about the compiler command lines.
There's the CMake File API, meant for IDE integration,
The CMAKE_EXPORT_COMPILE_COMMANDS option that creates a Clang-compatible compile_commands.json, and then there's
The CMAKE_<LANG>_COMPILER_LAUNCHER variables that would let you instrument a full command line with a custom script while the build is running.
One of these might be useful. The latter is commonly used with ccache, but can be (ab)used with any arbitrary program as long as the output file is eventually generated.
Note that the latter two only work with the Makefile and Ninja generators.
If you want the final output of how the source files will actually be compiled you will want to look at the generated files. I don't really know a better way currently:
Example:
Here is an example output from Ninja Multi
build\CMakeFiles\impl-Release.ninja
This file will list all of the compile definitions, compiler flags, include directories, object directory, etc.
Under the path "cmake-build-debug/CMakeFiles/" you'll find a folder named as "TopFolderOfYourProject.dir", where the cmake generates all its build system files, including a file "build.make". In this file you can see something like this:
CMakeFiles/somepath/somesourcefile.c
#$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=xxx\cmake-build-debug\CMakeFiles --progress-num=$(CMAKE_PROGRESS_1) "Building C object CMakeFiles/somepath/somesourcefile.c.obj"
Besides this, you can find extra info about the flags in the file "flags.make", it contains all extra compiler flags specified by developers.
And in "includes_C.rsp/includes_CXX.rsp" you can see the including path.
Build flags are, actually, associated with source files, because you can have differrent flags for different files. On the other hand, for the most cases these flags are equivalent.
Anyways, to get all build flags for a source file you can use COMPILE_FLAGS property:
get_source_file_property(RESULT file.cpp COMPILE_FLAGS)

CMake Fortran compiler-dependent flags

I'm using CMake for a moderate-sized Fortran project; sometimes I build it with gfortran, other times with ifort. When I want to do a debug build, the compiler flags are different; I'd like to have CMake automatically check which compiler is being used and set the flags accordingly.
It looks like this answer shows how to do the same thing for different C++ compilers. There's an example of how to check compilers with Fortran, using
if (Fortran_COMPILER_NAME MATCHES "gfortran.*")
However, this fails to invoke the conditional, because CMake has decided to use f95. Of course, f95 happens to alias to gfortran, but CMake doesn't detect that.
What's the right way to do this?
You can use also use CMAKE_Fortran_COMPILER_ID:
if ("${CMAKE_Fortran_COMPILER_ID}" MATCHES "Intel")
# something
elseif("${CMAKE_Fortran_COMPILER_ID}" MATCHES "GNU")
# something else
endif
Best way is to read file CMakeDetermineFortranCompiler.cmake and related files referenced from it.
Rather than trying to special case for different compilers you should actually test that your compiler supports the flags you want to set using check_fortran_compiler_flag like so:
include(CheckFortranCompilerFlag)
check_fortran_compiler_flag("-my-flag" _my_flag)
if(_my_flag)
set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -my-flag")
endif()
This is both safer and (I think) simpler because you don't need the implied knowledge of which compiler (and version) supports which flag.
It's simple. Only indicate the full path of compiler installed e.g.gfortran. the code: cmake -DCMAKE_fortran_PATH=/usr/bin/gfortran

CMake and clang_complete

I'm wanting to setup my CMakeLists.txt file so that it can generate the .clang_complete file required by the vim plugin clang_complete.
Ordinarily, you would do this by passing a parameter to the python script it supplies with the compiler and all of the parameters for compilation. Note that I am omitting the actual directory cc_args.py is in to save on space.
cc_args.py gcc test.c -o test -I~/IncludeDirs/
You can also do this during the make phase...
make CC='cc_args.py gcc' CXX='cc_args.py g++'
However, I am unsure of how to (if it is possible to) set this up within a CMakeLists.txt file. It's really annoying to have to type this in every time I want to setup clang_complete. The reason why I want to do it this way, is because I have multiple projects that I use a custom script to build the CMakeLists.txt file, so having to write a script for each one or manually place a generic one is a step I'd like to avoid.
I've tried a couple of things that have so far have come up with errors.
I've tried setting CMAKE_CC_COMPILER and CMAKE_CXX_COMPILER to lines similar to the first i.e. "cc_args.py g++". The errors that come up here say that It can't find the compiler (which is understandable).
The next thing I tried was setting the Compiler variables just to the cc_args.py and adding a flag for the actual compiler: suffice to say, that failed horribly. CMake said that it couldn't compile a test program (considering the script isn't a compiler, and the tests don't use the flags I set, I'm not surprised at this).
So without writing any other external scripts that require moving around, is there anyone that can think of a way that can do this?
The solution is to set the CXX environment variable before executing cmake. Something like that:
CXX="$HOME/.vim/bin/cc_args.py clang++" cmake ..
make
See http://www.guyrutenberg.com/2013/01/29/vim-creating-clang_complete-using-cmake/ for more details.
I know you said "without writing any other external scripts," but it seems like you just need a one-liner:
exec cc_args.py g++
And then set that file as your CMAKE_CXX_COMPILER. You could even use CMake's file() function to write the one-liner at build time if you don't want to have to distribute it.

CMake : how to link a library WITHOUT automatic search function FIND_PACKAGE?

I wonder how to find/link a library without any FIND_PACKAGE.
Assume that we have a "personal" library called testlib :
/perso/testlib/include/testlib1.h
/perso/testlib/include/testlib2.h
/perso/testlib/lib/testlib1.a
/perso/testlib/lib/testlib2.a
How to link it with CMake ?
1) What are the functions to link it directly in the code of the CMakeLists.txt ?
2) How to allow the user to select where are the files ?
3) I have difficulties to understand what is interpreted and what it's not by CMake. For example if you define a variable ${MYVARIABLE_INCLUDE_DIR} or ${MYVARIABLE_LIBRARIES} is "INCLUDE_DIR" or "LIBRARIES" an extension interpreted by CMake or there is no difference if I call this variable ${MYVARIABLE_INCDIR} ?
4) How to do the same procedures (including a "personal" library) if you have a library that contains ten library files or more in the lib directory ?
5) And finally, when you type TARGET_LINK_LIBRARIES(myexecutable gmp), how do you know that the name of the library is "gmp". Why not "Gmp" or "GMP" ? Is the name of the library to put in this function just equal to the .a file minus "lib" and ".a" ? For example libgmp.a -> gmp ? If I want to link a library called libtestlolexample.a, do I have to type TARGET_LINK_LIBRARIES(myexecutable testlolexample) ?
Thank you very much.
You can use target_link_libraries(myexecutable mylib) to link to the library "mylib". The compiler will use its default way to find the specified library (e.g. it will look for libmylib.a on Linux). The compiler will only look in the link_directories(directory1 directory2 ...), so you could try that command to add the required directories to the search path.
When "mylib" is also compiled with CMake this will be recognized and everything should work automatically.
When you want the user to specify a directory you can use a cached CMake variable. set(MYPATH "NOT-DEFINED" CACHE PATH "docstring").
For more complex stuff it is very advisable to write a CMake find module that can be used with find_package. I suggest you take a look at the FindALSA.cmake which can be used as a good starting point.
The interesting part is at the end:
if(ALSA_FOUND)
set( ALSA_LIBRARIES ${ALSA_LIBRARY} )
set( ALSA_INCLUDE_DIRS ${ALSA_INCLUDE_DIR} )
endif()
mark_as_advanced(ALSA_INCLUDE_DIR ALSA_LIBRARY)
The ALSA_LIBRARY and ALSA_INCLUDE_DIR variables are user configurable and stored in the cache, while ALSA_LIBRARIES and ALSA_INCLUDE_DIRS as well as ALSA_FOUND get computed and are the ones that the user of the find module is supposed to use.
Typically one would use the find module like this:
find_package(ALSA REQUIRED)
include_directories(${ALSA_INCLUDE_DIRS})
target_link_libraries(myexe ${ALSA_LIBRARIES})
I'm sure you can adapt this for your personal library.
Usually when you want to link against a library that doesn't have a find_package module (e.g. it's an uncommon library, or it's your own library), then you can use the basic commands (the find_X commands) to set variables with the paths you need. Then you use those variables as with find_package (include_directories, target_link_libraries).
If you're going to be using this library from multiple packages, you may want to create a find_package module; basically it's using the same commands with certain conventions.
Either of these allow you to specify paths (in the CMake module) to look in, and they allow the user to override the paths (the variables show up as options in ccmake/cmake-gui).
I'd be glad to add an example of one or both of these methods, just let me know what you're looking for.
If you just want a quick-and-dirty solution, you could do this, but I wouldn't recommend it:
include_directories(/perso/testlib/include)
add_executable(myexecutable myexecutable.cpp)
target_link_libraries(myexecutable
/perso/testlib/lib/testlib1.a
/perso/testlib/lib/testlib2.a)
Regarding your question about target_link_libraries (#5), you can do it several ways. If you want you can provide the full name (e.g. target_link_libraries(myexe libfoo.a)), but I think it's better (more portable I suppose) to use the short name (e.g. target_link_libraries(myexe foo). You can also include linker flags; I'm not sure where I read it, but I think it may translate the -L and -l flags for different linkers.
For example, if I have a bunch of libraries in the same directory, and I know the names, I might find the directory, store it in a variable, and then do this:
# First, find and set TESTLIB_LIBRARY_DIR, e.g. with find_path
# ...
# This assumes the libraries are e.g. 'libtestlib1.a' and 'libtestlib2.a'
set(TESTLIB_LIBRARIES
-L${TESTLIB_LIBRARY_DIR)
-l testlib1
-l testlib2)
add_executable(myexecutable myexecutable.cpp)
target_link_libraries(myexecutable ${TESTLIB_LIBRARIES})
If you want to make your own find_package module (like trenki mentioned, FindALSA.cmake seems to be a good starting point), you can use it by adding the directory to the CMAKE_MODULE_PATH; for example, if you put your module(s) in a cmake/modules/ subdirectory:
# Look for extra CMake modules in a subdirectory of this project
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/" ${CMAKE_MODULE_PATH})
One possible issue with FindALSA.cmake: I'm not sure CMAKE_CURRENT_LIST_DIR will work. So I think you should make this change (the second work for me in a module I wrote):
# Change this line
include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
# To this (with no path/extension it will search the CMake modules path):
include(FindPackageHandleStandardArgs)
And to get the usage of FIND_PACKAGE_HANDLE_STANDARD_ARGS, look at FindPackageHandleStandardArgs.cmake in the CMake Modules directory.
CMake has a good documentation.
Static linkage (if i understand you correct) is archived by passing the STATIC keyword to add_library
I would suggest to not do that (I'm not a CMake expert) but it sounds like the expense would be to large.
There is no difference, ${MYVARIABLE_INCLUDE_DIR} ist just a variable name it whatever you want. But i would suggest that you follow the naming convention.
One libary is always one .lib/.a file so there should be no problem just use the add_library& target_link_libraries& add_dependencies function.
The library name is always the name that you pass to add_library. However Gmp or gMP would be the same as CMake is case intensitive