0

I am working on a library with the tree looking something like(file names have been changed a little bit for simplicity):

.
├── CMakeLists.txt
├── include
│   └── proj_name
│       ├── core
│       │   ├── file00.h
│       │   ├── file01.h
│       │   ├── ...
│       │   ├── ...
│       │   └── filen.h
│       └── core.h
└── src
    ├── file00.c
    ├── file01.c
    ├── ...
    ├── ...
    └── filem.c

Now, I need to created a shared library, so I have written the CMakeLists as:

cmake_minimum_required(VERSION 3.5)

project(module VERSION 1.0.0)

include(GNUInstallDirs)
add_library(module SHARED
        src/file00.c
    src/file01.c
        src/...
        src/...
        src/filem.c
)

set_target_properties(module PROPERTIES
                VERSION ${PROJECT_VERSION}
                SOVERSION 1
                PUBLIC_HEADER include/proj_name/core.h)

target_include_directories(proj_name PRIVATE include)
target_include_directories(proj_name PRIVATE src)

install(TARGETS proj_name
        LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
        PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/proj_name)

The issue starts from here onwards. This CMakeLists is generating the shared objects in the /usr/local(as expected) shown below:

.
├── include
│   └── proj_name
│       └── core.h
└── lib
    ├── ...
    ├── libcore.so -> libcore.so.1
    ├── libcore.so.1 -> libcore.so.1.0.0
    └── libcore.so.1.0.0

But inside the include subdirectory only core.h is copied, to use my library I have to manually copy the ./include/proj_name/core directory into /usr/local.

Q1. Is there a way in which I can do that with the help of CMakeLists only?
Q2. In future I am planning to extend my library and the whole tree(at top) is just a single module. If I want to install the library as:

/usr/local/include/proj_name/proj_name.h
/usr/local/include/proj_name/module1.h
/usr/local/include/proj_name/module2.h
...

How should I write the CMakeLists?

[EDIT]: I forgot to mention the tree structure for my future library:

.
├── include
│   └── proj_name
│       └── proj_name.h
├── module1
│   ├── CMakeLists.txt
│   ├── include
│   │   └── proj_name
│   │       ├── module1
│   │       │   ├── file00.h
│   │       │   └── file01.h
│   │       └── module1.h
│   └── src
│       ├── file00.c
│       └── file01.c
├── module2
│   ├── CMakeLists.txt
│   ├── include
│   │   └── proj_name
│   │       ├── module2
│   │       │   ├── file00.h
│   │       │   └── file01.h
│   │       └── module2.h
│   └── src
│       ├── file00.c
│       └── file01.c
└── module3
    ├── CMakeLists.txt
    ├── include
    │   └── proj_name
    │       ├── module3
    │       │   ├── file00.h
    │       │   └── file01.h
    │       └── module3.h
    └── src
        ├── file00.c
        └── file01.c
  • Not sure what is a problem. Just enumerate `include/proj_name/module1.h` and `include/proj_name/module2.h` files in the `PUBLIC_HEADER` property, as you have already done for `include/proj_name/core.h` header. – Tsyvarev Oct 28 '20 at 14:43
  • @Tsyvarev Sorry if the question was not clear above. So what I am trying to say is for the question #1 I want to edit the CMakeLists such that I don't have to copy `include/proj_name/module*/*.h` files manually to `/usr/local`. And for the second question, I have modified my question. Hope my question is clear now. – Leforgè Tronifier Oct 28 '20 at 16:06
  • Still don't understand your problem. You **know** how to **install a single header** `include/proj_name/core.h` into `/usr/local/include/proj_name/proj_name.h` and succeed in that installation. Now you **want** to **install headers** `/usr/local/include/proj_name/module1.h` and `/usr/local/include/proj_name/module2.h` too. What is wrong in following the same approach (`PUBLIC_HEADER`) using which you have already installed the header `/usr/local/include/proj_name/proj_name.h`? – Tsyvarev Oct 28 '20 at 16:12
  • 1
    Btw: `target_include_directories(proj_name PRIVATE include)` is impractical, if you want to include the lib as part of another project. If projects linking the lib need access to this include dir, do `target_include_directories(proj_name PUBLIC include PRIVAT src)` and projects including `proj_name` via `target_link_libraries` automatically gain access to those headers. – fabian Oct 28 '20 at 17:42
  • @Tsyvarev Can you please take a quick look at my error at https://github.com/dev-tronifier/cmake_tests , BTW, thanks for you previous comment, I was able to resolve the issue, but Q1 still remains. – Leforgè Tronifier Oct 28 '20 at 17:59
  • 1
    "Can you please take a quick look at my error at ..." - The error is about missed header ``module3/file00.h``. You don't install that header, so what else do you expect? It seems I am becoming to understand your problem... Do you want to install **all headers** in the directory without manually specifying them in `CMakeLists.txt`? If this is actually your intention, then see that question: https://stackoverflow.com/questions/48212771/cmake-install-header-files-and-maintain-directory-heirarchy. – Tsyvarev Oct 28 '20 at 19:31
  • @Tsyvarev I have updated my repo, it is working r.n. and thanks for your comment earlier, this is what I needed([used here](https://github.com/dev-tronifier/cmake_tests/blob/main/module1/CMakeLists.txt#L15)). But I still want to remove the dependency of subdirectory-source file [written here](https://github.com/dev-tronifier/cmake_tests/blob/main/CMakeLists.txt#L11). – Leforgè Tronifier Oct 29 '20 at 03:32

1 Answers1

0

Thanks to @Tsyvarev, I was able to do the following myself, I was just rather confused in a way or two. I have created a repo with the sample for the future project here. So, I have created the CMakeLists at root node as:

cmake_minimum_required(VERSION 3.5)

project(proj_name VERSION 1.0.0)

include(GNUInstallDirs)

add_subdirectory(module1)
add_subdirectory(module2)
add_subdirectory(module3)

add_library(proj_name SHARED
    module1/src/file00.c module1/src/file01.c
    module2/src/file00.c module2/src/file01.c
    module3/src/file00.c module3/src/file01.c)

set_target_properties(proj_name PROPERTIES
                VERSION ${PROJECT_VERSION}
                SOVERSION 1
                PUBLIC_HEADER include/proj_name/proj_name.h)

install(TARGETS proj_name
        LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
        PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/proj_name)

As for those CMakeLists.txt inside the modules, they go something like:

cmake_minimum_required(VERSION 3.5)

add_library(module1 SHARED src/file00.c src/file01.c)

set_target_properties(module1 PROPERTIES
        VERSION ${PROJECT_VERSION}
        SOVERSION 1)

target_include_directories(module1 PUBLIC include)
target_include_directories(module1 PRIVATE src)

install(TARGETS module1
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})

install(DIRECTORY "${CMAKE_SOURCE_DIR}/module1/include/proj_name"
    DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})

Now, I think all the lines are self-explainatory, for more info read README at here.

Important Note: If you have another way to do so, please feel free to give an answer, for that I am not closing the question yet.