[CMake] C header file cross dependency
Wagner Martin
Martin.Wagner at neuberger.net
Tue May 31 10:35:27 EDT 2016
Thank you for your answer!
> > 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.
>
> This is not a cmake-problem, but seems to be a code-structure-issue.
>
> I'm guessing here: if terminal needs the uart-code shouldn't it be the
> uart-code filling in a terminal-function. Interface vs. implementation?
> Could you elaborate more on how terminal and uart are linked?
The terminal code implements a "printf()" equivalent function to log debug and state information. All input is then directly written to the UART.
The UART driver now wants to use this terminal logging function. It doesn't care how printf() works.
In the end, this is necessary because there is no file system to store the log information to. I would like to have this:
uart_write(uart2) -> syslog(prio, errormsg) -> syslog.txt on file system.
But I have:
uart_write(uart2) -> printf(errormsg) -> uart_write(uart1) -> PC with running terminal software
>
> Regarding cmake: I suggest you stop using include_directories() and
> start using target_include_directories() and
> target_compile_definitions() instead of add_definitions().
I will have a look at this.
>
> Limiting yourself to this way of doing libraries and targets, cmake will
> force you to structure your code in a more standard way - and will
> provide you with clean visibility between different targets.
>
> Could you provide a working, stripped down example to show the problem
> provided via github (in an example repo).
I will try to do this within a few days...
>
> More comments below.
>
> > 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})
>
> I think it is common practice now to use lower-case for cmake-commands
> now.
OK.
>
> > ## 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}}
> > )
>
> While the ${${var}${var2}} (seems to) work, it is error-prone, IMHO.
>
> Standard cmake-commands can work with relative paths and are evaluating
> them correctly taking into account ${CMAKE_CURRENT_SOURCE_DIR} (most of
> the time. So you could use ../uart in terminal/
This is what I did to continue working...
> - but it would be better
> if it comes indirectly via target_include_directories() and
> target_link_libraries()
...and this is why I asked the list :-)
>
> >[..]
> >
> > 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)
>
> Due to the circular header-dependency the binaries of terminal and uart
> should have the same mutual dependency. In this case you could build
> them in within one target.
Yes, I could do that. But I wanted to get away from one single, monolithic makefile...
This is why I created one CMake file for every functional unit of my source code (drivers, RTOS, terminal and so on).
regards,
Martin
More information about the CMake
mailing list