开发者

Global variables in CMake for dependency tracking

Hallo,

I'm using CMake as build system in one of my projects which is quite complex. The project includes several libraries and several applications. My goal is, to make the following possible:

  1. Libraries may be built on request by user (realised by cached CMake variable)
  2. Applications are built on request by user (see above), but an application may select which libraries are required and build them without the user selecting them
  3. This should not change the cached user selection on which libraries to build (to disable building the libraries automatically if the application building is turned off)

My build system layout is the following: I have a parent directory which contains a CMakeLists.txt that adds the libraries and applications as subdirectory. Each library and application has its own CmakeLists.txt which defines the user definable configuration options to be stored in cache, the targets to be built and on which other libraries of the project it depends. Applications are not necessarily located in the next subdirectory of the parent directory, but could also be some levels lower, so that I cannot make use of PARENT_SCOPE, because the parent hasn't to be the topmost parent, but the dependencies have to be known on top.

I tried setting GLOBAL properties like PROJECT_BUILD_SOMELIBRARY set to on and tried to retrieve them in SOMELIBRARY's CMakeLists.txt to decide whether to build or not, but the properties didn't get passed on to the library, so it never built even if it in fact would have had to, because another library or application indicated that it depended on this library. Using a LIST containing the name of each application or library target depending on a library and caching that one internally didn't work either.

To sum these many words up, I'm looking for a way to influence a CMakeLists in some subdirectory responsible for building a library by a CMakeLists in some other subdirectory (which isn't necessarily the same subdirectory level as th开发者_如何学运维e other subdir) to build that library, even if the user didn't specify it explicitly via the configuration option on cmake invocation.

Does someone know how this could be achieved or is this impossible with CMake? Are there suggestions for other approaches towards this problem that, however, include using CMake? Do you know of any other build system that could handle this requirements comfortably?

Many thanks, crispinus


One way to make global CMake variables is:

set(EXAMPLE_INCLUDE_DIRS CACHE INTERNAL "include directories" FORCE)

Than when you want to append or set the value use:

  set(EXAMPLE_INCLUDE_DIRS ${EXAMPLE_INCLUDE_DIRS } ${EXTRA_INCLUDE_DIRS }
CACHE INTERNAL "include directories") 


I created an example online that attempts to answer this question. You should be able to download it my GitHub repository at bgoodrs-CMake-Examples. If you click on that link, you can read the document (README.markdown in that repository) that attempts to do the same kinds of things that I think that you want to do. You may click the download button to download a copy of the examples for local experimentation. If that missed the mark, then comment on my answer, and I'll try to improve the example accordingly.


I solved the problem by myself in meantime. In fact, it was quite straightforward to implement the setup I explained above. I used the EXCLUDE_FROM_ALL option to all targets depending on whether they were explicitly selected by user (=leave out the EXCLUDE_FROM_ALL) or not.

The EXCLUDE_FROM_ALL option has the effect that a target is not included in the all-Target, unless another target (which is not marked as EXCLUDE_FROM_ALL) depends on this target. This works even over subdirectories, because CMake targets are really global and even the topmost parent knows about the bottommost subdirectory's target, and even a subdirectory at the same level knows about the targets of another subdirectory.

In my layout, each separate part of my project contains its own CMakeLists.txt and adds its own options to the cache, so a sample subproject would look this way:


SET(PART_NAME SAMPLE_PART)
SET(PART_TARGET_NAME samplepart)

SET(BUILD_${PART_NAME} off CACHE BOOL "Build part ${PART_NAME}")
SET(${PART_NAME}_FILES some_file.c another_file.c)

IF(NOT BUILD_${PART_NAME})
SET(EXCLUDE_${PART_NAME} EXCLUDE_FROM_ALL)
ENDIF(NOT BUILD_${PART_NAME})

ADD_LIBRARY(${PART_TARGET_NAME} SHARED ${EXCLUDE_SAMPLE_PART} ${PART_NAME}_FILES)
TARGET_LINK_LIBRARY(${PART_TARGET_NAME} some_other_target)

So if the user chooses to BUILD_SAMPLE_PART, the target is not set to EXCLUDE_FROM_ALL and will be included in all; if not, the target is set to EXCLUDE_FROM_ALL and will be built only if another target depends on this. If this target is build, also the "some_other_target" will be built, whether it's included in all by itself or not.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜