I'm using CMake to build a shared library, however for the Windows DLL I need the versioning information, like:
FileDescription
FileVersion
InternalName
LegalCopyright
OriginalFilename
ProductName
ProductVersion
So far, all I have are the VERSION and SOVERSION properties, but these don't seem to correlate to the FileVersion information I was expecting.
set(LIC_TARGET MySharedLib)
add_library(${LIC_TARGET} SHARED ${SOURCES} )
SET_TARGET_PROPERTIES(${LIC_TARGET}
PROPERTIES
VERSION ${MY_PRODUCT_NUMBER}.${MY_PRODUCT_VERSION}.${MY_BUILD_NUMBER}
SOVERSION ${MY_PRODUCT_NUMBER})
I've found manual methods (see example at the bottom) but would prefer to contain this within CMake.
Help?
You could use your CMake variable values in conjunction with a version.rc.in file and the configure_file command.
// version.rc.in
#define VER_FILEVERSION #MY_PRODUCT_NUMBER#,#MY_PRODUCT_VERSION#,#MY_BUILD_NUMBER#,0
#define VER_FILEVERSION_STR "#MY_PRODUCT_NUMBER#.#MY_PRODUCT_VERSION#.#MY_BUILD_NUMBER#.0\0"
#define VER_PRODUCTVERSION #MY_PRODUCT_NUMBER#,#MY_PRODUCT_VERSION#,#MY_BUILD_NUMBER#,0
#define VER_PRODUCTVERSION_STR "#MY_PRODUCT_NUMBER#.#MY_PRODUCT_VERSION#.#MY_BUILD_NUMBER#\0"
//
// ...along with the rest of the file from your "manual methods" reference
And then, in your CMakeLists.txt file:
# CMakeLists.txt
set(MY_PRODUCT_NUMBER 3)
set(MY_PRODUCT_VERSION 5)
set(MY_BUILD_NUMBER 49)
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/version.rc.in
${CMAKE_CURRENT_BINARY_DIR}/version.rc
#ONLY)
set(LIC_TARGET MySharedLib)
add_library(${LIC_TARGET} SHARED ${SOURCES}
${CMAKE_CURRENT_BINARY_DIR}/version.rc)
# Alternatively you could simply include version.rc in another rc file
# if there already is one in one of the files in ${SOURCES}
I'm had same problem and have automated version generation for my projects.
You need three files from github:
generate_product_version.cmake
VersionInfo.in
VersionResource.rc
Put it in cmake subdirectory of your project and make sure to include it to CMAKE_MODULE_PATH like:
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake)
Then before add_executable() or add_library(SHARED) your target, use:
include(generate_product_version)
generate_product_version(
VersionFilesOutputVariable
NAME "My Great Project"
ICON ${PATH_TO_APPLICATION_ICON}
VERSION_MAJOR 1
VERSION_MINOR 3
VERSION_PATCH ${BUILD_COUNTER}
VERSION_REVISION ${BUILD_REVISION}
)
Full list of supported resource strings see in generate_product_version.cmake.
VersionInfo.h and VersionResource.rc will be generated to cmake binaries folder. Variable VersionFilesOutputVariable will hold paths to these files. Just add this list to your target:
add_executable(MyGreatProject ${your-target-sources} ${VersionFilesOutputVariable})
UPDATE: Corrected generate_product_version script parameters from VERSION_PATH
to VERSION_PATCH.
There is an even easier way than the accepted answer. It does not involve transforming an input resource.rc.in. Simply create a generic version.rc file as described here and then from your CMakeLists.txt do this:
#CMakeLists.txt
add_definitions(-DVER_COMPANYNAME_STR="MyCompany")
add_definitions(-DVER_FILEVERSION_STR="1,1,0.0")
# ...
# add all the other defines here
set(LIC_TARGET MySharedLib)
add_library(${LIC_TARGET} SHARED ${SOURCES} version.rc)
This has the added benefit that the defines are accessible from your source code as well, so you have programmatic access to your version.
Related
I'm using the -imacros option for GCC in order to set all preprocessor defines (Options) for a project.
Before imacros I have been using a raw file with the preprocessor defines names and with a regular expression in CMAKE I was creating the list of -D to put in the CMAKE_C_FLAGS.
This works fine but ugly to see in the text editor. So to enhance that, I have changed to -imacros.
CMAKE_C_FLAGS will contain -imacros "path to configuration header"
This works fine, but if I change some configuration item in the configuration header the CMAKE do not recompile the file (don't see changes). In the old version - as you can expect - if some -D was changed all the files will be recompiled.
Any help?
An simple Approach
You can use OBJECT_DEPENDS source file property. But that needs to be set for all source files with something like:
set_source_files_properties(
${sources}
PROPERTIES
OBJECT_DEPENDS "path to configuration header"
)
Alternatives for all Source Files in Project
Officially CMake recommends to put all your definitions in a header file that is included by all your source files. The header could e.g. be generated from a template using configure_file().
But to follow your line of thought with using -imacros compiler flag, here are two alternative approaches for triggering a rebuild of all source files if "path to configuration header" file changes:
You can extend the scope of OBJECT_DEPENDS to all targets and their source files in the current directory with define_property(... INHERITED ...):
If the INHERITED option then the get_property() command will chain up to the next higher scope when the requested property is not set in the scope given to the command. DIRECTORY scope chains to GLOBAL. TARGET, SOURCE, and TEST chain to DIRECTORY.
So in your case this translates to:
define_property(
SOURCE
PROPERTY OBJECT_DEPENDS
INHERITED
BRIEF_DOCS "brief-doc"
FULL_DOCS "full-doc"
)
set_directory_properties(
PROPERTIES
OBJECT_DEPENDS "path to configuration header"
)
If I understand correctly, you anyway have to re-run CMake if your "configuration header" should/would change. Then you can simply add one definition outside your "configuration header" that keeps track of the header with something like:
file(TIMESTAMP "path to configuration header" _timestamp)
add_definitions(-DIMACROS_TIMESTAMP=${_timestamp})
Now every time your header gets a new timestamp, the definitions for all targets are changing and your build system will rebuild all source files.
I'm following a tutorial on CMake and I have problems understanding the necessity of using the 'include_directories' command at one point.
Let me explain the project first:
In my working directory I have:
- a main.cpp function, a CMakeLists.txt(the main one), a configuration file, a 'MathFunction' directory and a 'build' directory
In the MathFunction directory I have:
- a CMakeLists.txt file that will be invoked by the main one
- A file 'mysqrt.cxx' that contains the implementation of a function which will be used in 'main.cpp' application
- A 'MathFunctions.h' header file that contains the prototype of that function
In the CMakeLists from 'MathFunction' directory I'm creating a library using code from 'mysqrt.cxx' like this:
add_library(MathFunctions mysqrt.cxx)
This snippet is a part of my main CMake code:
# add the MathFunctions library?
#
if (USE_MYMATH)
include_directories ("${PROJECT_SOURCE_DIR}/MathFunctions") # WHY DO WE NEED THIS
add_subdirectory (MathFunctions)
set (EXTRA_LIBS ${EXTRA_LIBS} MathFunctions)
endif (USE_MYMATH)
add_executable(Tutorial tutorial.cxx)
target_link_libraries (Tutorial MathFunctions)
Now I do not understand why I need too add that 'include_directories' command in order to use the library? Shouldn't it be enough that the last command 'target_link_libraries' links the already created executable and libraries togheter so there would be no need to also include_directories?
Thank you for reading and I'm sorry if I have not explained it very well but I hope you will understand what I mean :D
Command include_directories sets directories for header files (.h) to be searched. Linking (target_link_libraries) with a library basically specifies only a library file (.so, .dll or other type). As you see, these are different things.
When linking executable with a library target, CMake propagates (more precisely, "consumes") some properties of that library target to the executable. Among these properties there is INTERFACE_INCLUDE_DIRECTORIES property, which adds include directories to the executable.
So, when a library target has INTERFACE_INCLUDE_DIRECTORIES property correctly being set, you don't need to explicitly specify include directories for executable:
MathFunctions/CMakeLists.txt:
add_library(MathFunctions mysqrt.cxx)
# Among other things, this call sets INTERFACE_INCLUDE_DIRECTORIES property.
target_include_directories(MathFunctions PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
CMakeLsits.txt:
add_executable(Tutorial tutorial.cxx)
# This also propagates include directories from the library to executable
target_link_libraries (Tutorial MathFunctions)
Note, that using simple
# This *doesn't* set INTERFACE_INCLUDE_DIRECTORIES property.
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
in MathFunctions/CMakeLists.txt doesn't imply propagating include directories to the linked executable.
VĂsual Studio >=2010 does provide to configure system directories in the VC++ Directories section. Is there any way to tell CMake to fill these settings instead using C/C++/Additional Include Directories?
Since cmake 3.12 you can use variables like CMAKE_VS_SDK_INCLUDE_DIRECTORIES to setup "VC++ Include Directories".
Simply add the following line to your CMakeLists.txt:
include_directories(-your-include-folder-)
Similarly, add the following line if you want to set the library directories:
link_directories(-your-library-folder-)
As Min said, you can set CMAKE_VS_SDK_INCLUDE_DIRECTORIES now. Thank you Min!
I'll leave a working example for the next person that ends up here like I did.
cmake_minimum_required(VERSION 3.18)
# ...
if (MSVC)
# Example for a library that only exports as module without xxx_DIRS variables.
get_target_property(SDL2_image_INCLUDE_DIRS SDL2_image::SDL2_image INTERFACE_INCLUDE_DIRECTORIES)
# Join all include dependencies in a list
set(_DEPS_DIRS ${SDL2_INCLUDE_DIRS} ${SDL2_image_INCLUDE_DIRS} ${OpenCV_INCLUDE_DIRS})
# Make all slashes turn into backslashes
cmake_path(CONVERT "${_DEPS_DIRS}" TO_NATIVE_PATH_LIST _NATIVE_DIRS NORMALIZE)
# Set the "VC++ Directories > Include Directories" setting
set(CMAKE_VS_SDK_INCLUDE_DIRECTORIES "$(VC_IncludePath);$(WindowsSDK_IncludePath)" ${_NATIVE_DIRS})
unset(_DEPS_DIRS)
unset(_NATIVE_DIRS)
endif()
Important: To troubleshoot first delete the build folder and start from scratch.
I believe previously (before v3.18?) cmake added the list to the "Additional Include Directories" setting, but I think they removed it because those are added with /I compiler option, and now it seems included dependencies are added with /external:I if you look at Command Line settings in the project, and they may conflict? Not confirmed, just a thought.
Don't use target_include_directories or include_directories just for this. With modules you shouldn't need to, only use it if you already had to.
Also even if possible shouldn't include all headers as dependencies to add_executable, that's inconvenient.
I have a library "lib" and an executable "demo".
The issue I'm having is that "demo" can't get lib_INCLUDES and lib_LIBS lib variables, set by "lib". I want them set because in demo.h I do #include <lib.h> and it fails to find the include. I want CMake to make lib.h a global include, i.e. pass -I /path/to/the/dir/with/lib.h/ to the compiler.
Source tree:
- src/
- CMakeLists.txt
- lib/
- CMakeLists.txt
- lib.cpp
- lib.h
- demo/
- CMakeLists.txt
- demo.cpp
- demo.h
src/CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
project(test)
add_subdirectory(lib)
add_subdirectory(demo)
src/lib/CMakeLists.txt
add_library(lib SHARED lib.h lib.cpp)
target_include_directories(lib ${CMAKE_CURRENT_SOURCE_DIR})
# defined for later use in src/demo/CMakeLists.txt
set(lib_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR})
set(lib_LIBS lib)
src/demo/CMakeLists.txt
include_directories(${lib_INCLUDES})
add_executable(demo demo.h demo.cpp)
target_link_libraries(demo ${lib_LIBS})
# empty! why?
message(STATUS ${lib_INCLUDES})
Tell me how "demo" can access lib_INCLUDES and lib_LIBS libraries set by "lib", they seem to be empty in src/demo/CMakeLists.txt.
I don't want src/demo/CMakeLists.txt contain paths to "lib", only src/lib/CMakeLists.txt should know details of "lib" and it should define nice variables for use in src/demo/CMakeLists.txt that hide all those details.
Please include a working CMakeLists.txt in your answer, if possible.
Please read carefully documentation of SET command. Your variable lib_INCLUDES has local scope to lib\CMakeLists.txt, so for example you can CACHE it.
Better way is to populate INTERFACE_INCLUDE_DIRECTORIES of lib by
target_include_directories(lib INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
so the target_link_libraries automatically appends lib's include directories.
I'm running into a problem with add_custom_command for a custom target (created using add_custom_target).
My general idea is to incorporate a static code analysis tool into the cmake tool-chain. My solution is based on the one described here: https://github.com/rpavlik/cmake-modules/blob/master/CppcheckTargets.cmake
In a nutshell, each project that I want to run static code analysis for has the following two lines of code:
include(cppcheck)
add_cppcheck(${le_project} STYLE POSSIBLE_ERROR FAIL_ON_WARNINGS)
The module has this at the top of the file:
if (NOT TARGET ANALYZE_CODE)
add_custom_target(ANALYZE_CODE WORKING_DIRECTORY ${LE_LITEN_ROOT})
set_target_properties(ANALYZE_CODE PROPERTIES EXCLUDE_FROM_ALL TRUE)
endif ()
and later on in the function the custom command is added:
add_custom_command(TARGET
ANALYZE_CODE
PRE_BUILD
COMMAND
${CPPCHECK_EXECUTABLE}
${CPPCHECK_QUIET_ARG}
${CPPCHECK_TEMPLATE_ARG}
${_cppcheck_args}
${_files}
WORKING_DIRECTORY
"${CMAKE_CURRENT_SOURCE_DIR}"
COMMENT
"${_name}_cppcheck: Running cppcheck on target ${_name}..."
VERBATIM)
The problem I'm seeing is that the command is only added for the project that included the file first. I'm not sure why and what is going on. I verified the following using message() commands:
The target is only created once
The add_custom_command is run for every project that calls the function, with proper arguments
But when I actually look at the target in visual studio, only the first include / function call command is added.
If the file is only included without calling the function, no custom commands are added at all.
Desired behavior:
I would like ONE target named "ANALYZE_CODE" to run all commands added by calls to the function.
I.e. if 3 projects include the two lines from above, the target ANALYZE_CODE is created once but 3 custom commands are added to it, one for each project.
It turns out you're somewhat stuck between a rock and a hard place here. The issue I think boils down to a couple of factors.
Firstly, although the docs don't make it clear, add_custom_command(TARGET ...) only works for targets created in the same directory. So the first subproject to call include(cppcheck) is the only one which can effectively add custom commands to the target ANALYZE_CODE.
A workaround for this might seem to be to move all calls to add_cppcheck from their respective subdirectories up to the top-level CMakeLists file.
include(cppcheck)
add_cppcheck(${le_first_project} STYLE POSSIBLE_ERROR FAIL_ON_WARNINGS)
add_cppcheck(${le_second_project} STYLE POSSIBLE_ERROR FAIL_ON_WARNINGS)
...
This isn't a great solution, since these really belong inside their own subdirs. But a bigger issue is that properties on source files only persist in the scope of the CMakeLists.txt in which they are added. This isn't obvious at all, but from the docs for set_source_files_properties:
Source file properties are visible only to targets added in the same directory (CMakeLists.txt).
The innards of the add_cppcheck have the following block of code:
foreach(_source ${_cppcheck_sources})
get_source_file_property(_cppcheck_lang "${_source}" LANGUAGE)
get_source_file_property(_cppcheck_loc "${_source}" LOCATION)
if("${_cppcheck_lang}" MATCHES "CXX")
list(APPEND _files "${_cppcheck_loc}")
endif()
endforeach()
So this is checking that each source file for the given target is designated as a C++ file before adding it to the list of files to be given to cppcheck. If this function is invoked from within the CMakeLists.txt where the target is defined (i.e. the subdir) then the files all have the appropriate property and are correctly added.
However, if the function is called from the parent CMakeLists.txt, the files have lost their properties, and so none are added and cppcheck is passed an empty list!
Now for the possible fixes. There are probably few ways to get out of this hole - I can point to a couple.
You could continue with the option to always call add_cppcheck from the top-level CMake file and avoid using the source files' properties. So the problem codeblock above could be changed to something more like:
set(CxxExtensions .cpp .CPP .cc .CC .cxx .CXX)
foreach(_source ${_cppcheck_sources})
get_filename_component(Extension "${_source}" EXT)
list(FIND CxxExtensions "${Extension}" IsCxxFile)
if(IsCxxFile GREATER -1)
list(APPEND _files "${_source}")
endif()
endforeach()
You could even enforce that the function is only called from the top-level CMakeLists.txt by adding something like this at the start of the function:
if(NOT "${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}")
message(FATAL_ERROR "This can only be called from the top-level CMakeLists.txt")
endif()
The second fix (which I'd personally favour) is to leave the add_cppcheck calls inside the subdirs and have the function add a custom target rather than command. These targets can successfully be applied as dependencies of the top-level target ANALYZE_CODE. So for example, change the add_custom_command to something like:
add_custom_target(ANALYZE_${_name}
${CPPCHECK_EXECUTABLE}
${CPPCHECK_QUIET_ARG}
${CPPCHECK_TEMPLATE_ARG}
${_cppcheck_args}
${_files}
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
COMMENT "ANALYZE_${_name}: Running cppcheck on target ${_name}..."
VERBATIM)
add_dependencies(ANALYZE_CODE ANALYZE_${_name})
set_target_properties(ANALYZE_${_name} PROPERTIES FOLDER "Code Analysis")
This should cause building ANALYZE_CODE to trigger building each of the subordinate ANALYZE_... targets.
It has the downside of "polluting" the solution with a lot of extra targets, but an upside is that you could use these targets in the add_test calls (although this may be a step too far):
# CMake 2.8.0 and newer
add_test(NAME ${_name}_cppcheck_test
COMMAND ${CMAKE_COMMAND}
--build ${CMAKE_BINARY_DIR}
--target ANALYZE_${_name})