I am still a CMake newbie (started learning 3 days ago). In my current CMakeLists.txt, I have the following set directives:
[...]
SET(CPACK_GENERATOR "RPM")
SET(CPACK_PACKAGE_VERSION_MAJOR "3")
SET(CPACK_PACKAGE_VERSION_MINOR "3")
SET(CPACK_PACKAGE_VERSION_PATCH "svn")
SET(CPACK_SYSTEM_NAME "0.el6.x86_64")
[...]
Once I run make package, I got a libcxx-3.3.svn-0.el6.x86_64.rpm.
But IMHO this is "cheating".
According to http://fedoraproject.org/wiki/Packaging:NamingGuidelines#Package_Naming_and_Versioning_Guidelines, ideally I should be able to generate a libcxx-3.3-0.el6.x86_64.rpm instead. But this demands that CPack not to show the CPACK_PACKAGE_VERSION_PATCH.
Nevertheless, according to my trial results, it doesn't seem to be feasible. I would appreciate a hint as to how.
Did you try setting CPACK_PACKAGE_FILE_NAME (without the extension) to the desired name? This is provided so that you can define your own package naming scheme if the default does not suit your needs. See http://www.cmake.org/Wiki/CMake:CPackConfiguration for more details on key CPack variables and what they do.
Related
In our project, we have a large number of configurations stemming from a large variety of target hardware types multiplied by few modes.
To avoid unneeded details let's just assume that the configurations have form <hw>_<mode> were
<hw> is one of: A, B or C,
<mode> is one of: 1, 2 or 3.
Furthermore, to remain close to actual case let's assume that A_3 and C_1 are unsupported exceptions. (However, I don't think it matters here.)
Which leaves us with 3 x 3 - 2 = 7 supported configurations.
Now, we would like to make settings (amongst others also the path to compiler and sysroot) depend on the configuration. Also, some sources should be included only in some configurations. And we would prefer to do it based on parts of the configuration.
For example, we would like to use /this/g++ for all A_* configurations and /that/g++ for all other. Or we would like to add mode2.cpp file for all *_2 configurations but not others.
It is a simple task if we use CMAKE_BUILD_TYPE. We can split it with regex (string(REGEX MATCH) and have variables with each part. Then simple if does the job.
However, such approach is not friendly with multi-config generators (it seems currently those are only Visual Studio and Xcode). To play nicely with multi-config generators, AFAIK, we would have to use generator expressions.
The problem is, however, that I see no way to extract parts for the configuration (CONFIG) in the generator expressions.
For example, I can do this:
add_executable(my_prog
source_1.cpp
# ...
source_n.cpp
$<$<CONFIG:A_2>:mode2.cpp>
$<$<CONFIG:B_2>:mode2.cpp>
$<$<CONFIG:C_2>:mode2.cpp>
)
but this doesn't look like a maintainable approach considering that sooner or later we will be adding new hardware types (or removing obsolete ones).
Is there any way to do some form of matching in generator expression?
The only workaround I found out so far is to use an approach like this:
set(CONFIG_IS_MODE_2 $<OR:$<CONFIG:A_2>,$<CONFIG:B_2>,$<CONFIG:C_2>>)
add_executable(my_target
source_1.cpp
# ...
source_n.cpp
$<${CONFIG_IS_MODE_2}:mode2.cpp>
)
which at least allows centralizing those expressions and when new hardware type is added there is a single place to update. However, still, there are many variables to update.
Is there any better solution?
With target_sources() command and a function() you could still use a regex to match your configurations.
This would look something like in this example code:
cmake_minimum_required(VERSION 3.0)
project(TestConfigRegEx)
function(my_add_sources_by_config_regex _target _regex)
foreach(_config IN LISTS CMAKE_CONFIGURATION_TYPES CMAKE_BUILD_TYPE)
if (_config MATCHES "${_regex}")
target_sources(${_target} PRIVATE $<$<CONFIG:${_config}>:${ARGN}>)
endif()
endforeach()
endfunction()
file(WRITE main.cpp "int main() { return 0; }")
file(WRITE modeRelease.cpp "")
add_executable(my_target main.cpp)
my_add_sources_by_config_regex(my_target Release modeRelease.cpp)
But that gives me an error from CMake version 3.11.1 Visual Studio 15 2017 generator side:
Target "my_target" has source files which vary by configuration. This is
not supported by the "Visual Studio 15 2017" generator.
Config "Debug":
.../main.cpp
Config "Release":
.../main.cpp
.../modeRelease.cpp
Strange enough it still generates the solution.
Alternatives
The classic one would be adding a define containing the configuration and handle the differences in the C/C++ code with #if checks
You differentiate not per configuration but with additional targets (like my_target and my_target_2)
Disclaimer: I'm aware of this question. However, The OP's needs are different to mine: what he actually wants is to port an app to Linux and therefore the answers go in that line, not answering what I want to know: the reasons of the error.
I'm trying to create a dropdown list in CMake GUI following the instructions in here and here
So I have this very simple CMakeLists.txt:
cmake_minimum_required(VERSION 3.6)
project(datasetprograms)
set(CMAKE_CXX_STANDARD 11)
#LINES TO MAKE THE GUI DROP-DOWN:
set(TARGET_ARCHITECTURE “arm” CACHE STRING “Architecture to compile to”)
set_property(CACHE TARGET_ARCHITECTURE PROPERTY STRINGS arm x86)
#Add subdirectories for each project
add_subdirectory(helloworld)
Basically I just copied and pasted, following the instructions. However, instead of having a nice drop-down in the CMake GUI, I got the following error:
CMake Error at CMakeLists.txt:9 (set_property): set_property could
not find CACHE variable TARGET_ARCHITECTURE. Perhaps it has not yet
been created
Question: What I'm doing wrong?
You may check value of variable TARGET_ARCHITECTURE using message() and you will found CACHE is a part of that value.
This is because you use in set() command double quotes which are not common ones (") but language-specific (“). So CMake treats set() command as not CACHE'd one. That is a reason of the error message.
I'm trying to edit the CPack settings so that the outputted package file has the correct version number in it. But that's not all. I'd like CMake/CPack to have all the places where the version number is updated also be set. The .so file should also be set. And whatever else needs it.
From where I sit, the CPack documentation appears to be telling us to repeat ourselves.
If I do nothing, the output file is like so:
mystuff-0.1.1-Linux.tar.gz
Let's say the version number should be 1.2.3.
I would think that this is the minimalistic CPACK settings to cause all the version numbers to be changed -- and I placed these lines in my CMakeLists.txt file:
SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "My app is great")
SET(CPACK_PACKAGE_VENDOR "My Name")
SET(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README.md")
SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
SET(CPACK_PACKAGE_VERSION_MAJOR "1")
SET(CPACK_PACKAGE_VERSION_MINOR "3")
SET(CPACK_PACKAGE_VERSION_PATCH "2")
When I build, the output file is still mystuff-0.1.1-Linux.tar.gz
If I repeat myself and do this:
SET(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
Now that variable is set, but the file is still mystuff-0.1.1-Linux.tar.gz
It seems that I must also change CPACK_PACKAGE_FILE_NAME
What other places do I have to re-state the version number?
This doesn't feel idiomatic. I must be missing something to make this automatic. Am I supposed to specify the variable at an earlier point in time? I also see some projects on the internet containing a CPackConfig.cmake file -- the file contains overrides, but I still see some repeating oneself going on in those as well.
This bug also mentions the same thing. Apparently, they do want us to repeat ourselves. (as of 2015) However, even if that is the case, I was wondering if anyone has found a work-around?
If no work around, how about a way to re-state all the variables so that they end up automatically set correctly? For instance, doing the following is a way to compose the version number by using the variables
SET(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
According to the documentation, the file name is composed like this:
SET(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${CPACK_SYSTEM_NAME}")
There are probably other variables that need re-setting. If I have to restate everything, then exactly what do I need to restate to be complete?
Make sure that you have the following line after setting the CPACK_... variables:
include (CPack)
This is the spot where CPACK_PACKAGE_FILE_NAME and others are automatically set, so the version variables (such as CPACK_PACKAGE_VERSION_MAJOR) must be already set at this point.
If you set your project's version via https://cmake.org/cmake/help/v3.0/command/project.html, you can set the cpack version like
set(CPACK_PACKAGE_VERSION_MAJOR ${PROJECT_VERSION_MAJOR})
set(CPACK_PACKAGE_VERSION_MINOR ${PROJECT_VERSION_MINOR})
set(CPACK_PACKAGE_VERSION_PATCH ${PROJECT_VERSION_PATCH})
include(CPack)
You'll probably want to look at the documentation for the PROJECT() command, which has a VERSION field. I'm not sure if it is wired through to CPack, but at least that is the idiomatic place for setting the project version.
https://cmake.org/cmake/help/v3.0/command/project.html
I have a program on my computer, let's say C:/Tools/generate_v23_debug.exe
I have a FindGenerate.cmake file which allows CMake to find that exact path to the executable.
So in my CMake code, I do:
find_program(Generate)
if (NOT Generate_FOUND)
message(FATAL_ERROR "Generator not found!")
So CMake has found the executable. Now I want to call this program in a custom command statement. Should I use COMMAND Generator or COMMAND ${GENERATOR_EXECUTABLE}? Will both of these do the same thing? Is one preferred over the other? Is name_EXECUTABLE a variable that CMake will define (it's not in the FindGenerate.cmake file), or is it something specific to someone else's example code I'm looking at? Will COMMAND Generator be expanded to the correct path?
add_custom_command(
OUTPUT blahblah.txt
COMMAND Generator inputfile1.log
DEPENDS Generator
)
find_program stores its result into the variable given as a first argument. You can verify this by inserting some debug output:
find_program(GENERATOR Generate)
message(${GENERATOR})
Note that find_program does not set any additional variables beyond that. In particular, you mentioned Generate_FOUND and GENERATOR_EXECUTABLE in your question and neither of those gets introduced implicitly by the find_program call.
The second mistake in your program is the use of the DEPENDS option on the add_custom_command. DEPENDS is used to model inter-target dependencies at build time and not to manipulate control flow in the CMakeLists. For example, additional custom command can DEPEND on the output of your command (blahblah.txt), but a custom command cannot DEPEND on the result of a previous find operation.
A working example might look something like this:
find_program(GENERATOR Generate)
if(NOT GENERATOR)
message(FATAL_ERROR "Generator not found!")
endif()
add_custom_command(
OUTPUT blahblah.txt
COMMAND ${GENERATOR} inputfile1.log
)
P.S.: You asked why the code examples were not properly formatted in your question. You indented everything correctly, but you need an additional newline between normal text and code paragraphs. I edited your question accordingly.
I have a project with 4 different sub projects. To specify the versions, I use the
SET(parent_VERSION_MAJOR 1)
SET(parent_VERSION_MINOR 0)
set(parent_VERSION_PATCH 0)
set(parent_VERSION 1.0.0)
and then I can use this in the sub projects if the add_subdirectory is used.
Q1. I could not set parent_VERSION based on MAJOR, MINOR and PATCH. According to the documentation is should be set automatically but whenever I try printing it, it is empty without using the last line in the code.
Q2. In case I want to build from sub directory only, I get an error shouting :
CMake Error at CMakeLists.txt:28 (set_target_properties):
set_target_properties called with incorrect number of arguments.
which is because I am using parent_VERSION there.
So I understand that it isn't able to get the parent_VERSION without running cmake from the top directory but how do I change the code such that it can build even without running from the top level.
I read about SET with INHERITED but I don't think that is what I need.
Here is how I solved it. If someone could tell me a better/more elegant way I'd be happy.
if(NOT parent_VERSION)
SET(parent_VERSION_MAJOR 1)
SET(parent_VERSION_MINOR 0)
SET(parent_VERSION_PATCH 0)
SET(parent_VERSION 1.0.0)
endif(NOT parent_VERSION)