[CMake] C header file cross dependency

Wagner Martin Martin.Wagner at neuberger.net
Mon May 23 09:49:14 EDT 2016


Hi @all,

I'm quite new to CMake. If I've made a mistake or something is much easier to solve, please tell me.

I'd like to use CMake in embedded development (Build System: Linux, Target: ARM Microcontroller) to get rid of complicated makefiles.

We're building multiple devices where stuff like embedded rtos and peripheral drivers are identical, so I'd like to separate this part from the user application. I've achieved that by creating an object library out of all source and header files, and packing those files using CPack. This archive is then statically linked against the user application.

So far this worked fine. However, now I have to use driver functions in the rtos source code and vice versa, resulting in cross-dependencies for header files:

<drivers/uart.c>

#include uart.h
#include terminal.h

function() {}

<os/terminal.c>

#include terminal.h
#include uart.h

function() {}

How do I resolve something like this? Right now CMake evaluates the compiler includes in the order that subdirectories are added. This gives me an compilation error in uart.c that terminal.h cannot be found.

Thank you for your help!

Regards,
Martin



Some excerpt of my project. I've tried to keep the example as simple as possible.

My directory structure looks something like that:
/
CMakeLists.txt
src +
    +CMakeLists.txt            (1)
    +drivers+
    |       +uart.c
    |       +uart.h
    |       +...
    |       +CMakeLists.txt    (2)
    +os-----+
    |       +terminal.c
    |       +terminal.h
    |       +...
    |       +CMakeLists.txt    (3)


(1):

SET(drivers "drivers")
SET(terminal "terminal")

SET(drivers_lib ${drivers})
SET(terminal_lib ${terminal})

SET(ARCHIVE_INSTALL_DIR lib)
SET(INCLUDE_INSTALL_DIR include)

SET(headers_private "_headers_private") # internal headers
SET(headers_public "_headers_public")   # public headers go into package

ADD_SUBDIRECTORY(${drivers})
ADD_SUBDIRECTORY(${terminal})

## ---- Targets -------------------------------------------------------------------
ADD_LIBRARY(bsp ${object_libs})
INSTALL(TARGETS bsp DESTINATION ${ARCHIVE_INSTALL_DIR})

(2):

## drivers

## ---- Sources -------------------------------------------------------------------
SET(sources 
          "uart.c"
)

## ---- Header includes -----------------------------------------------------------
SET(headers
          "${CMAKE_CURRENT_SOURCE_DIR}/" 
)
SET(${drivers}${headers_public} ${headers} PARENT_SCOPE)

INCLUDE_DIRECTORIES(${headers} 
                    ${${terminal}${headers_public}}
)

## ---- Targets -------------------------------------------------------------------
ADD_LIBRARY(${drivers_lib} OBJECT ${sources})
# add to list of Object Targets
SET(object_libs ${object_libs} $<TARGET_OBJECTS:${drivers_lib}> PARENT_SCOPE)

INSTALL(DIRECTORY ${headers} DESTINATION ${INCLUDE_INSTALL_DIR} FILES_MATCHING PATTERN "*.h")

(3), mostly like (2):

## rtos

## ---- Sources -------------------------------------------------------------------
SET(sources 
        "terminal.c"
)

## ---- Header includes -----------------------------------------------------------
SET(headers
          "${CMAKE_CURRENT_SOURCE_DIR}/"
)
SET(${terminal}${headers_public} ${headers} PARENT_SCOPE)

INCLUDE_DIRECTORIES(${headers} 
                    ${${drivers}${headers_public}}
)

## ---- Targets -------------------------------------------------------------------
ADD_LIBRARY(${terminal_lib} OBJECT ${sources})
# add to list of Object Targets
SET(object_libs ${object_libs} $<TARGET_OBJECTS:${terminal_lib}> PARENT_SCOPE)

INSTALL(DIRECTORY ${headers} DESTINATION ${INCLUDE_INSTALL_DIR} FILES_MATCHING PATTERN "*.h")



And finally this creates the package in root directory CMakeLists.txt:

SET(CPACK_PROJECT_CONFIG_FILE ${CMAKE_BINARY_DIR}/CPackOptions.cmake) # CPackOptions.cmake contains package file name
SET(CPACK_GENERATOR "TBZ2")
INCLUDE(CPack)


I've searched for a solution for this problem for ~1 day, most results only deal with one directional dependencies or link a shared library/executable at the end, which does not help me. 

When changing (2) "INCLUDE_DIRECTORIES" to

INCLUDE_DIRECTORIES(${headers} 
                    "/home/user/workspace/arm_bsp/src/terminal/"
)
compilation works as expected, but breaks independence of child folders to parent folders. I defenitively do not want to do that.

CMake Version is "cmake version 3.0.2" (stock Debian 8)




More information about the CMake mailing list