Re: [CMake] C header file cross dependency
Hi @all, I've finally found a solution to the problem. My solution is here: https://github.com/martinwag/test_cmake/tree/master What I did: - remove "OBJECT" library targets as they do not work in combination with interface libraries - added one install target per library, so I get one "lib*.a" archive per library (which is not what I need) - added an post install target as described here: stackoverflow.com/questions/9998679 . This step creates a "thin" archive, that is packed with the other archives at cpack-time. This archive can be used as single file when linking in the consuming stage. Regards, Martin -- Powered by www.kitware.com Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ Kitware offers various services to support the CMake community. For more information on each offering, please visit: CMake Support: http://cmake.org/cmake/help/support.html CMake Consulting: http://cmake.org/cmake/help/consulting.html CMake Training Courses: http://cmake.org/cmake/help/training.html Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html Follow this link to subscribe/unsubscribe: http://public.kitware.com/mailman/listinfo/cmake
Re: [CMake] C header file cross dependency
Hi Patrick, thank you for your answer and sorry that it took me a while to work on it. > > I forked your repo and played a little bit around. > > https://github.com/pboettch/test_cmake I pulled those changes and played aroud a bit myself. https://github.com/martinwag/test_cmake I'm now back at the point where I decided to use cmake's OBJECTS functionality. I didn't find any other way to pack all compiled products into an easy-to-include-and-link package for the application. I was unable to use target_link_libraries() because this actually wants to do linking instead of just packaging. The way you used it add_library(bsp INTERFACE) target_link_libraries(bsp INTERFACE drivers terminal) install(TARGETS bsp DESTINATION ${ARCHIVE_INSTALL_DIR}) the install command runs, but does not install anything, resulting in an archive with just the headers. I'm open to package the archive in a different way - install(EXPORT ...) seems promising. The important thing to me is that the consuming application doesn't need inside knowledge of the bsp package. > > Here are my conclusions: > > 1) Due to the use of add_libary(... OBJECTS ...) you cannot link > libraries with libraries or interfaces, this is a pity - especially for > a complex project with a lot of sub-dirs. > > There is a possibility to merge STATIC-libraries to generated one big > archive using external tools (libtool). If I were you I'd try to this > way to profit from the target_*-cmake-features. See above. > > 2) I created a log-dir with an interface-library - which only carries > the log.h and thus the printf-prototypes > > 3) Both, drivers and terminal link with this interface-library (to get > their hands on log.h) > This sounds good - I have to check if that works in the (more complex) production code. > 4) In addition I added two libraries to drivers/ uart-logging1 and uart- > logging2. This shows how you could compile-configure your printf- > function depending on the hardware used. In the main CMakeLists you just > need to select one of them - depending on the option's value. > > Basically I followed the idea of instantiating a print-function > 'somewhere' in the project (it could also be done outside) and then > select the one you want to use at the final link. > > Of course this way you could add other ways of printf'ing - logging1 and > logging2 are just stupid examples. This is -more or less- already in my production code. I want to do all this stuff in one configuration header file inside the application. However, I think it's a good idea to have the option to replace the printing function with "anything". I removed that part to keep the example as simple as possible. > > HTH and sorry for the delay, Obviously I'm not the fastest myself :-). Regards, Martin -- Powered by www.kitware.com Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ Kitware offers various services to support the CMake community. For more information on each offering, please visit: CMake Support: http://cmake.org/cmake/help/support.html CMake Consulting: http://cmake.org/cmake/help/consulting.html CMake Training Courses: http://cmake.org/cmake/help/training.html Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html Follow this link to subscribe/unsubscribe: http://public.kitware.com/mailman/listinfo/cmake
Re: [CMake] C header file cross dependency
Hi Martin, On Wed, 1 Jun 2016 14:58:53 + Wagner Martinwrote: > > > > Could you provide a working, stripped down example to show the > > problem provided via github (in an example repo). > > > > I've added a simple test project to > > https://github.com/martinwag/test_cmake/tree/master > > Note that this example does not need cross gcc for ARM. It doesn't > implement any useful functionality! I forked your repo and played a little bit around. https://github.com/pboettch/test_cmake Here are my conclusions: 1) Due to the use of add_libary(... OBJECTS ...) you cannot link libraries with libraries or interfaces, this is a pity - especially for a complex project with a lot of sub-dirs. There is a possibility to merge STATIC-libraries to generated one big archive using external tools (libtool). If I were you I'd try to this way to profit from the target_*-cmake-features. 2) I created a log-dir with an interface-library - which only carries the log.h and thus the printf-prototypes 3) Both, drivers and terminal link with this interface-library (to get their hands on log.h) 4) In addition I added two libraries to drivers/ uart-logging1 and uart-logging2. This shows how you could compile-configure your printf-function depending on the hardware used. In the main CMakeLists you just need to select one of them - depending on the option's value. Basically I followed the idea of instantiating a print-function 'somewhere' in the project (it could also be done outside) and then select the one you want to use at the final link. Of course this way you could add other ways of printf'ing - logging1 and logging2 are just stupid examples. HTH and sorry for the delay, -- Patrick. -- Powered by www.kitware.com Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ Kitware offers various services to support the CMake community. For more information on each offering, please visit: CMake Support: http://cmake.org/cmake/help/support.html CMake Consulting: http://cmake.org/cmake/help/consulting.html CMake Training Courses: http://cmake.org/cmake/help/training.html Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html Follow this link to subscribe/unsubscribe: http://public.kitware.com/mailman/listinfo/cmake
Re: [CMake] C header file cross dependency
> > Could you provide a working, stripped down example to show the problem > provided via github (in an example repo). > I've added a simple test project to https://github.com/martinwag/test_cmake/tree/master Note that this example does not need cross gcc for ARM. It doesn't implement any useful functionality! Regards, Martin -- Powered by www.kitware.com Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ Kitware offers various services to support the CMake community. For more information on each offering, please visit: CMake Support: http://cmake.org/cmake/help/support.html CMake Consulting: http://cmake.org/cmake/help/consulting.html CMake Training Courses: http://cmake.org/cmake/help/training.html Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html Follow this link to subscribe/unsubscribe: http://public.kitware.com/mailman/listinfo/cmake
Re: [CMake] C header file cross dependency
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 -- Powered by www.kitware.com Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ Kitware offers various services to support the CMake community. For more information on each offering, please visit: CMake Support: http://cmake.org/cmake/help/support.html CMake Consulting: http://cmake.org/cmake/help/consulting.html CMake Training Courses: http://cmake.org/cmake/help/training.html Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html Follow this link to subscribe/unsubscribe: http://public.kitware.com/mailman/listinfo/cmake
Re: [CMake] C header file cross dependency
On Mon, 23 May 2016 13:49:14 + Wagner Martinwrote: > 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. Good thing! > 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: > > > > #include uart.h > #include terminal.h > > function() {} > > > > #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. 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? Regarding cmake: I suggest you stop using include_directories() and start using target_include_directories() and target_compile_definitions() instead of add_definitions(). 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). 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. > ## 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/ - but it would be better if it comes indirectly via target_include_directories() and target_link_libraries() >[..] > > 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. regards -- Patrick. -- Powered by www.kitware.com Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ Kitware offers various services to support the CMake community. For more information on each offering, please visit: CMake Support: http://cmake.org/cmake/help/support.html CMake Consulting: http://cmake.org/cmake/help/consulting.html CMake Training Courses: http://cmake.org/cmake/help/training.html Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html Follow this link to subscribe/unsubscribe: http://public.kitware.com/mailman/listinfo/cmake