1

Let's assume I have a project with a series of libraries. I also need to generate a header file that will be used by all of these projects. So I created a CMake file, like this:

project(main)

add_subdirectory(sub_1)
add_subdirectory(sub_2)
# ...
add_subdirectory(sub_n)

add_custom_command(
    OUTPUT CustomHeader.h
    COMMENT "Generating custom header for all the libraries"
    COMMAND ...)

add_library(${PROJECT_NAME} STATIC ${OBJECT_LIST})

The problem is, that I don't know how to tell CMake to run my custom command (that generates this CustomHeader.h) before it would try to build the libraries in the subfolders.

I tried add_custom_target(TARGET MyPrebuild PRE_BUILD ...) but I'm running on Linux, and this option only works on Windows platform according to the documentation.

add_dependencies only work between targets, and not a target and a single file.

I could, in theory, add the header to be among the source files of the individual libraries (in the sub_1, .., sub_n folders) but it feels wrong, as the header is not required to be part of those libraries.

So I just have no idea how I can make a library depend on an include file, that is not part of it.

Any tips how I can overcome this problem?

2
  • I could, in theory, add the header to be among the source files of the individual libraries (in the sub_1, .., sub_n folders) but it feels wrong, as the header is not required to be part of those libraries. - What do you mean by "the header is not part of the library"? The header isn't used when compile the library? Or what? In any case you may create custom target for your custom command, and make libraries dependent from this target. Commented Nov 16, 2017 at 7:46
  • @Tsyvarev Thanks for the comment. What I meant, is that the generated header is not going to be exposed in the final library. Just like you wouldn't include stdio.h in your library, while you might very well use it during the compilation. Commented Nov 16, 2017 at 22:19

2 Answers 2

1

For make header file (re)built before a library in subdirectory is compiled, you may create target, which builds the file, and make the library dependent from the target:

# *CMakeLists.txt*
# ...
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/CustomHeader.h ...)

add_custom_target(generate_custom_header DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/CustomHeader.h)

# *sub/CMakeLists.txt*
# ...
add_library(libA ...)

add_dependencies(libA generate_custom_header)

Instead of using add_dependencies, you may create header-only library which "implements" you header and link with it:

# *CMakeLists.txt*
# ...
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/CustomHeader.h ...)

add_custom_target(generate_custom_header DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/CustomHeader.h)

add_library(libCustom INTERFACE) # Header only library
add_dependencies(libCustom generate_custom_header) # which depends on generated header

# You may even assign include directories for the header-only library
target_include_directories(libCustom INTERFACE ${CMAKE_CURRENT_BINARY_DIR})

# *sub/CMakeLists.txt*
# ...
add_library(libA ...)

target_link_libraries(libA libCustom) # Common linking with a header-only library.

Note, that INTERFACE library is a "fake" - it is never created by itself. Instead, all "features" of INTERFACE library are just propagated to its users.

Sign up to request clarification or add additional context in comments.

Comments

0

I would suggest to add another library target that will both keep track of the generated headers and will help to properly configure other libraries to know where to find them (i.e. target_include_directories).

cmake_minimum_required(VERSION 3.0)
project(testable)

set(CustomHeaderInPath ${CMAKE_CURRENT_SOURCE_DIR}/CustomHeader.example)
set(CustomHeaderPath ${CMAKE_CURRENT_BINARY_DIR}/CustomHeader.h)

add_custom_command(
    OUTPUT ${CustomHeaderPath}
    COMMAND cp ${CustomHeaderInPath} ${CustomHeaderPath}
    COMMENT "Generated file"
    DEPENDS ${CustomHeaderInPath})

add_library(CustomHeaderLibrary ${CustomHeaderPath})
target_include_directories(CustomHeaderLibrary PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
set_target_properties(CustomHeaderLibrary PROPERTIES LINKER_LANGUAGE C)

add_library(LibA a.c)
target_link_libraries(LibA CustomHeaderLibrary)

add_library(LibB b.c)
target_link_libraries(LibB CustomHeaderLibrary)

add_executable(${PROJECT_NAME} main.c)
target_link_libraries(${PROJECT_NAME} PUBLIC LibA LibB)

Note that I had to explicitly set the LINKER_LANGUAGE of the new target as cmake won't be able to deduce it properly if no c or cpp files are added to the library.

1 Comment

thanks for the tip. I tried to do this, however, it does not work for me, as my libraries in the subfolder (I called sub_1, .., sub_n; you called LibA, LibB, ...) are defined as object libraries (add_library(LibB OBJECT ${SOURCES})) and CMake does not allow targt_link_libraries with object libraries.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.