CMake automatically recognizing new file extensions - cmake

When I add source files to a target they are automatically recognized if they are from the C/C++ file extensions. What I want to accomplish is that if I put in the sources xxx.foo all the .foo files are processed with a predefined set of compiler commands.
I know that the way to go is using add_custom_command but all the examples I have seen are using fixed filenames like the ones used here http://www.cmake.org/Wiki/CMake_FAQ#How_can_I_generate_a_source_file_during_the_build.3F
Any ideas about the right approach to the problem?

One way to approach the problem is to replace the plain CMake add_executable and add_library commands with wrapper functions or macros which do special processing of the files with the .foo extension and pass the other arguments and options through to the standard add_executable or add_library commands. E.g.:
set (FOO_SRCS "main.cpp" "module.cpp" "xxx.foo" "yyy.foo")
foo_add_executable(fooexec ${FOO_SRCS})
foo_add_library(foolib ${FOO_SRCS})
The FindCUDA standard CMake module takes that approach. It adds CUDA_ADD_EXECUTABLE and CUDA_ADD_LIBRARY commands which feed source files with the extension .cu to the NVIDIA C compiler.

Related

User-defined functions in another CMakeLists.txt file in CLion

I want to separate my user-defined functions from the main CmakeLists.txt so they are not in the way of my stuff.
I work in CLion primarily and want to have syntax highlight and code completion, which CLion provides for CMake.
How do I do this?
First you add another file alongside with your main CMakeLists.txt and name it something like: myfunctions.cmake.
*.cmake extension is recognized by CLion and enables CMake syntax highlight and code completion.
Then in your CMakeLists.txt you add line:
include(myfunctions.cmake)
Now you can use your user-defined functions in your main and all derived (from add_subdirectory) CMakeLists.txt files. Also you'll get CLion code completion for your user-defined functions as well (it works in CLion 2020.1, but I don't know about older versions)

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)

Pass target file name as compile definition in 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

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