41

I had a project which uses CMake as build tool and made a simple template for me and my collegues to use. As I searched for best and easy to use practices online, I've came across different approaches to make a library.

In this template, I've listed header files and source files in two seperate variables, and I'm not passing the headers to add_library command - just sources. And then I use set_target_properties with PUBLIC_HEADER variable to give the header-file list.

So far it seems to work, but I wonder if I'm making thing unnecessarily complex. Some people online give header files to add_library command as well and doesn't even use set_target_properties and such.

In short:

  • should we include header files to add_library or should we not (as a best practice)? And impacts of the two usage.
  • what is purpose being served by adding headers in the add_library/add_executable? As they seem working even without it (seems forward declaration and symbols only). confirm on understanding please.

(Here is the template I'm talking about:)

cmake_minimum_required(VERSION 3.1.0)

project(lae CXX C) 
set(CMAKE_CXX_STANDARD 14)

include_directories(
  ${CMAKE_CURRENT_SOURCE_DIR}
)

set(SOURCE_FILES
    ...
)

set(HEADER_FILES 
   ...
)

set( PRIVATE_HEADER_FILES
   ...
)

add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES} ) 

set( REQUIRED_LIBRARIES
   ...
)

target_link_libraries(${PROJECT_NAME} ${REQUIRED_LIBRARIES} )

SET_TARGET_PROPERTIES( 
  ${PROJECT_NAME}  
PROPERTIES 
  FRAMEWORK ON
  SOVERSION 0
  VERSION 0.1.0
  PUBLIC_HEADER "${HEADER_FILES}"
  PRIVATE_HEADER "${PRIVATE_HEADER_FILES}"
  ARCHIVE_OUTPUT_DIRECTORY "lib"
  LIBRARY_OUTPUT_DIRECTORY "lib"
  OUTPUT_NAME ${PROJECT_NAME}
)
parasrish
  • 3,466
  • 24
  • 29
Ahmet Ipkin
  • 752
  • 1
  • 8
  • 19
  • 2
    See also: https://stackoverflow.com/questions/13703647/how-to-properly-add-include-directories-with-cmake – Daniel Jun 15 '18 at 19:37

1 Answers1

22

In our projects we use a "simple" way of yours - add_library with both headers and sources.

If you add only sources, then you won't see headers in IDE-generated project.

However, when installing, we have to do it like that, using two install commands:

install(TARGETS library_name
        LIBRARY DESTINATION lib)

install(FILES ${PUBLIC_HEADERS} 
        DESTINATION include/library_name)

If you want to do it as a single command, you can use set_target_properties with PUBLIC_HEADER, as you suggested. Then, this kind of install is possible:

install(TARGETS library_name
        LIBRARY DESTINATION lib
        PUBLIC_HEADER DESTINATION include/library_name)

Choose the one you like the most and stick to it.

dreamzor
  • 5,715
  • 4
  • 39
  • 59
  • I liked the way you merged both! Also, saw the thing you mentioned (project files omit the headers thing) when export option used Eclipse CDT. I think I'll stick with your solution. Thanks! – Ahmet Ipkin Mar 23 '16 at 11:34
  • the second way of "install" doesn't seem working, when "headers" added/not-added in the add_library. It complains about `no targets specified, no makefile found` at build-make time. any clue? – parasrish Oct 27 '17 at 14:28
  • @parasrish If you don't define your headers with SET_TARGET_PROPERTIES command, since no headers are defined, it won't work. However, if you do SET_TARGET_PROPERTIES with "Public headers" are correctly set, install target should work properly. – Ahmet Ipkin Nov 07 '17 at 18:04
  • 1
    Visual Studio supports proper CMake and "Open Folder" since VS2017 and doesn't require headers listed in targets to be shown. CMake-generated VS projects aren't properly made for humans anyway and can confuse people when their changes in build configuration don't persist. Best modern practice should be to avoid opening CMake-generated VS solutions for development and remove headers from project sources – they aren't compiled sources and therefore noise. – WolleTD Sep 04 '19 at 19:52
  • 1
    This does not preserve include directory structure for my project. – Rich Henry Mar 03 '20 at 21:00