0

I'm in a similar situation to Adding object-file dependencies where it is mentioned:

... I need some object files that are part of the same library to be compiled before others.

Don't try to declare dependencies between object files. If there are files that have a dependency, break them out into a separate library with add_library and then declare the dependency with add_dependencies and target_link_libraries. There is no extra cost for doing this. Particularly, consider looking at Object Libraries.

I tried to implement this in my original project, where I'm working with a massive CMakeLists.txt file, where include & linker paths may be conditionally inserted or removed, and I failed. In essence, that CMakeLists.txt file would looks like this simplified:

project(MY_PROGRAM C CXX ASM)

set(MY_PROGRAM_sources
        main.c
        file_one.c
        file_two.c
        )

add_executable(MY_PROGRAM ${MY_PROGRAM_sources})

target_include_directories(MY_PROGRAM PRIVATE
        ${CUSTOM_PATH}/src/custom/include
        ...
        )

add_compile_options(-Wall
        -Wno-format
        ...
        )
        
target_link_libraries(MY_PROGRAM
        somelib1
        somelib2
        )

This builds fine, using Unix Makefiles.

Now, I've tried to extract file_one and file_two objects like this:

project(MY_PROGRAM C CXX ASM)

set(MY_PROGRAM_sources
        main.c
        #file_one.c
        #file_two.c
        $<TARGET_OBJECTS:SEPFILE_OBJS>
        )

add_library(SEPFILE_OBJS OBJECT
  file_one.c
  file_two.c
)

add_executable(MY_PROGRAM ${MY_PROGRAM_sources})

target_include_directories(MY_PROGRAM PRIVATE
        ${CUSTOM_PATH}/src/custom/include
        ...
        )

add_compile_options(-Wall
        -Wno-format
        ...
        )
        
target_link_libraries(MY_PROGRAM
        somelib1
        somelib2
        )

cmake passes fine here, but when I hit make, there is breakage as soon as file_one.c starts compiling:

...
[  9%] Building C object CMakeFiles/SEPFILE_OBJS.dir/file_one.c.obj
In file included from C:/tmp/file_one.c:14:
C:/tmp/file_one.h:19:10: fatal error: ExoticHeader.h: No such file or directory
   19 | #include <ExoticHeader.h>

Clearly, the SEPFILE_OBJS library did not inherit the include libraries nor other compilation/linker settings from the MY_PROGRAM executable.

I could probably repeat all target_* lines for SEPFILE_OBJS - but that looks quite unmanageable, plus my original CMakeLists.txt is huge, and I'd like to avoid that kind of work.

So is there a way to say to CMake "keep the same compilation and linker settings as in executable for MY_PROGRAM, also for the object library SEPFILE_OBJS"?

sdbbs
  • 4,270
  • 5
  • 32
  • 87
  • related: https://stackoverflow.com/questions/58759647/how-to-get-include-directories-from-a-target-for-use-in-add-custom-target – sdbbs Jan 18 '23 at 15:53
  • 1
    With use of `get_property`/`set_property` commands, you may try to copy properties like `INCLUDE_DIRECTORIES`, `COMPILE_OPTIONS`, `LINK_LIBRARIES`, etc. from MY_PROGRAM to SEPFILE_OBJS. The set of properties with "compiler and linker settings" is quite small, so it shouldn't be a problem to list them. Probably, instead of copying you could use "symlinks" via generator expressions: `set_target_properties(SEPFILE_OBJS PROPERTIES INCLUDE_DIRECTORIES $)`. – Tsyvarev Jan 18 '23 at 18:52

1 Answers1

1

I would do it the way around. I would first define a library section, including file_one.c and file_two.c, and then a main executable section, which would link against this library target.

I would also follow something along the lines below for a directory structure (ideally, I would put the source files within a src directory):

/ MY_PROGRAM
|- include
|   \- MY_PROGRAM
|       |- file_one.h
|       \- fine_two.h
|- file_one.c
|- file_two.c
|- main.c
\- CMakeLists.txt
  1. Put your header files in an include/${PROJECT_NAME} folder, and set an include_dir var pointing to it.
set(include_dir ${PROJECT_SOURCE_DIR}/include/${PROJECT_NAME})
  1. Define the list of library and application sources:
set(lib_sources
    "${CMAKE_CURRENT_SOURCE_DIR}/file_one.c"
    "${CMAKE_CURRENT_SOURCE_DIR}/file_two.c"
)
set(app_sources
    "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp"
)
  1. Library section. Define a lib_MY_PROGRAM target, and set the include directories, compile options, and link libraries for it. Notice it's better to use the target_... specific commands than the more general ones, such as add_compile_options:
add_library(lib_${PROJECT_NAME} ${lib_sources})
target_include_directories(lib_${PROJECT_NAME} PUBLIC
    "$<BUILD_INTERFACE:${include_dir}>"
    "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
)
target_include_directories(lib_${PROJECT_NAME} SYSTEM PUBLIC
    ${CUSTOM_PATH}/src/custom/include
)
target_compile_options(lib_${PROJECT_NAME} PRIVATE
    -Wall
    -Wno-format
)
target_link_libraries(lib_${PROJECT_NAME} PRIVATE
    somelib1
    somelib2
)
  1. Main binary section:
add_executable(${PROJECT_NAME} ${app_sources})
target_include_directories(${PROJECT_NAME} PUBLIC
    "$<BUILD_INTERFACE:${include_dir}>"
    "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
)
target_compile_options(lib_${PROJECT_NAME} PRIVATE
    -Wall
    -Wno-format
)
target_link_libraries(${PROJECT_NAME} PRIVATE lib_${PROJECT_NAME})
rturrado
  • 7,699
  • 6
  • 42
  • 62
  • 1
    Why list(APPEND app_sources ${lib_sources})? Doesn't this build the lib sources twice, once in the library and once in the application target? – Wutz Jan 18 '23 at 22:00
  • 1
    Ooops, many thanks for noticing! That line is not needed. Fixed. – rturrado Jan 18 '23 at 22:48