2

I currently have a very large file structure that I would like to port over to cMake, but unfortunately I am have a really difficult time finding examples similar to the file structure I am currently working with.

(the __.c/h means any file name)

Project
   Target
        <*.s19/*.elf goes here>
   Component1
        src
            file.c
            file.h
            ____.c
            ____.h
        cfg
            ____.c
            ____.h
        out
            <*.o goes here>
        tmp
            <*.d goes here>
   Component2
        src
            file.c
            file.h
            ____.c
            ____.h
        cfg
            ____.c
            ____.h
        out
            <*.o goes here>
        tmp
            <*.d goes here>
   Component3
        src
            file.c
            file.h
            ____.c
            ____.h
        cfg
            ____.c
            ____.h
        out
            <*.o goes here>
        tmp
            <*.d goes here>

Also, how would I tell it to look for includes in a certain component, like for example I want files in component 1 to only look for #includes in Component2. Also, how would I tell it to only compile in a certain list of files, for example within src, I may only want it to compile in file1.c, but not file2.c

  • 3
    I'd _strongly_ suggest not trying to mix binary and source directories like this. One of CMake's strongest features is the ability to do [out-of-source builds](http://www.cmake.org/Wiki/CMake_FAQ#What_is_an_.22out-of-source.22_build.3F), which can save you lots of maintenance headaches, especially when dealing with large projects. – ComicSansMS Feb 12 '14 at 08:40

1 Answers1

0

How to use different include directories in different components (with help of @ruslo and @steveire):

  1. In the main CMakeLists.txt add components in the right order:

    add_subdirectory(Component1)
    add_subdirectory(Component2)
    
  2. In the Component1/CMakeLists.txt add a property to the generated library::

    cmake_minimum_required(VERSION 2.8.11)
    
    ...
    
    add_library(Component1 ${Component1_SOURCES})
    target_include_directories(Component1 INTERFACE
      "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>"
      "$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>"
      ... other required includes
    )
    
  3. In the Component2/CMakeLists.txt use target_include_directories for the Component2:

    cmake_minimum_required(VERSION 2.8.11)
    
    ...
    
    add_executable(Component2 ${Component2_SOURCES})
    target_link_libraries(Component2 Component1)
    

Regarding exact list of files to be compiled. Frankly speaking I don't see any problem in this area. Simply specify them explicitly in the add_executable or add_library directives:

add_binary(Component1Binary test1.c test2.c test5.c)

But I should mention that traditionally CMake uses slightly different layout for compiled artifacts. It places either compiled artifacts right within the source directory, or you may create a totally separated directory and it will put all compiled artifacts there, completely reproducing your project structure. Take a look:

 MyProject/
     CMakeLists.txt <- the top-level CMakeLists.txt. It may simply `add_subdirectory()`s (for each of its `Components`) and configure project-wide settings
     Component1/
         CMakeLists.txt <- this is intented to build artifact(s) for Component1
         src1-1.c
         src1-1.h
         ...
     Component2/
         CMakeLists.txt <- this is intented to build artifact(s) for Component2
         src2-1.c
         src2-1.h
         ...

now you may create an empty directory with an arbitrary name (say, build.release) anywhere in your filesystem (usually somewhere within MyProject but not necessary), then cd to that directory and call cmake like this:

 cmake [cmake flags like -DCMAKE_BUILD_TYPE=Release and others] path/to/the/MyProject

CMake then creates all required Makefile-s and other build artifacts in this directory and you may call make (or ninja if you've chosen to use ninja instead of make) and all build artifacts would reside in that directory, reproducing the original structure of MyProject:

build.release/
     Component1/
         src1-1.o
         ...
         Component1.a
     Component2/
         src2-1.o
         ...
         Component2Exe

etc

More on $<BUILD_INTERFACE:...> stuff is in docs, How to set include_directories from a CMakeLists.txt file? etc. The feature is relatively new and I still not sure that I did everything absolutely correctly (the test example does compile though).

Community
  • 1
  • 1
user3159253
  • 16,836
  • 3
  • 30
  • 56
  • 2
    You don't need to manage include_directories like that. Encode them into the component1 target, not into a variable. Then target_link_libraries automatically consumes them. Simply set(CMAKE_INCLUDE_CURRENT_DIR ON) – steveire Feb 12 '14 at 09:36
  • Thank you! It seems I've missed these changes in CMake development (I've just checked, it's available since 2.8.8-2.8.11). Although I couldn't get "automatic" behaviour with just `target_link_libraries`, there's a solution with two `target_include_directories`. I will update the answer and please re-check my solution – user3159253 Feb 12 '14 at 10:49
  • You should be able to remove the target_include_directories in step 3. See http://www.cmake.org/cmake/help/git-next/manual/cmake-buildsystem.7.html. File a bug if you have a non-working testcase. – steveire Feb 12 '14 at 15:22
  • Well, it seems that CMake-2.8.12.1 installed on my computer doesn't mind against INTERFACE, but you're right, PUBLIC is perfectly enough for this case. Also, with PUBLIC it's possible not to specify `target_include_directories` in the Component2. So I'm updating the answer, hopefully, finally. – user3159253 Feb 13 '14 at 16:27
  • Then I don't understand the whole idea. With PUBLIC I do receive the expected result, at least in the simple test application and CMake-2.8.12.1. Or maybe I miss something? – user3159253 Feb 14 '14 at 16:27