CMake Adding Headers to Projectfile

2019-08-05 14:14发布

问题:

Ok so I have the following code in my root/CMakeLists.txt.

cmake_minimum_required(VERSION 2.8)

if(NOT CMAKE_BUILD_TYPE)
    set(CMAKE_BUILD_TYPE Release CACHE STRING "Debug or Release" FORCE)
endif()

if(CMAKE_CONFIGURATION_TYPES)
    set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "Configurations" FORCE)
    mark_as_advanced(CMAKE_CONFIGURATION_TYPES)
endif()

execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory install)
SET(CMAKE_INSTALL_PREFIX install)

project(efge)

# include
add_definitions(-DEFGE_EXPORTS)
include_directories("${CMAKE_SOURCE_DIR}/include/EFGE/"
            "${CMAKE_SOURCE_DIR}/include/EFGE/Math"
            "${CMAKE_SOURCE_DIR}/include/EFGE/System")

# preconf
set(EFGE_SHARED_LIBS TRUE CACHE BOOL "Shared libraries (needs shared SFML libraries, too)")

if(WIN32)
    set(EFGE_STATIC_STD_LIBS FALSE CACHE BOOL "Statically linked runtime/standard libraries? Must match with SFML-Option.")
    if(EFGE_STATIC_STD_LIBS)
        if(EFGE_SHARED_LIBS)
            message("\nEFGE_STATIC_STD_LIBS and EFGE_SHARED_LIBS aren\'t compatible!")
        elseif(MSVC)
            foreach(flag CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE)
                if(${flag} MATCHES "/MD")
                    string(REGEX REPLACE "/MD" "/MT" ${flag} "${${flag}}")
                endif()
            endforeach()
        elseif(CMAKE_COMPILER_IS_GNUCXX)
            set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++")
        endif()
    endif()
endif()

if(CMAKE_COMPILER_IS_GNUCXX)
    set(CMAKE_CXX_FLAGS "${CMAKE_CSS_FLAGS} -std=c++0x")
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -stdlib=libc++")
    add_definitions(-DEFGE_USE_STD_RANDOMENGINE)
endif()

set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/Modules/;${CMAKE_MODULE_PATH}")

if(NOT EFGE_SHARED_LIBS)
    set(SFML_STATIC_LIBRARIES TRUE)
endif()
find_package(SFML 2 COMPONENTS audio graphics window system)

if(SFML_FOUND)
    include_directories(${SFML_INCLUDE_DIR})
else()
    set(SFML_ROOT "" CACHE PATH "SFML top-level directory")
    message("\n SFML directory not found. Please set SFML_ROOT to SFML top-level path, wich contains /include/ and /lib/ directories.")
    message("Make sure SFML libraries have the same configuration.")
endif()

# linking sfml
macro(efge_link_sfml EFGE_TARGET)
    target_link_libraries(${EFGE_TARGET} ${SFML_LIBRARIES})
endmacro()
macro(efge_link_sfml_dependencies EFGE_TARGET)
    target_link_libraries(${EFGE_TARGET} ${SFML_DEPENDENCIES})
endmacro()

macro(efge_link_efge EFGE_TARGET)
    target_link_libraries(${EFGE_TARGET} efge)
endmacro()

# source
add_subdirectory(src)

# include
install(DIRECTORY include
        DESTINATION .)

My file structure, if this is important, is the following:

+-- include
       +-- Math
            +--- *.hpp files
       +-- System
            +--- *.hpp files
       +--- *.hpp files
+-- src
     +--- *.cpp files
     +--- CMakeLists.txt
+--- CMakeLists.txt

How can I add the headers to my generated projectfile (e.g. CodeBlocks) ? Makefile seems to work fine. Stuff like set_group do not affect the projectfile. I can't figure it out, using CMake for the first time. Thanks!

回答1:

I've just checked the following combination:

  1. CMake 2.8.12.1
  2. CodeBlocks 13.12

CodeBlocks project was generated as follows:

mkdir build
cd build
cmake -G 'CodeBlocks - Unix Makefiles' ..

and I do see that the generator produced a .cbp file with all headers files listed in. So you may view the .cbp file and check if headers are listed. If they're not, then you should check if your CMake is fresh enough.

Update:

Ahha, I see. It seems I've reproduced your problem with the generator. Here's the minimal non-working example:

project/
   CMakeLists.txt
   src/
        CMakeLists.txt
        test.cpp
   include/test.h

project/CMakeLists.txt:

cmake_minimum_required(VERSION 2.8)

project(TestProject)

include_directories(include)

add_subdirectory(src)

project/src/CMakeLists.txt:

cmake_minimum_required(VERSION 2.8)

project(TestProjectSources)

set(SOURCES test.cpp)

add_executable(test ${SOURCES})

project/src/test.cpp

#include "test.h"

int main(void) {
    TestRun r;
    r.run();
    return 0;
}

project/include/test.h:

#ifndef _TEST_H_
#define _TEST_H_

#include <iostream>

class TestRun {
public:
    TestRun() { std::cout << "Hello World!" << std::endl; }
    void run() { std::cout << "Doing something useful" << std::endl; }
};

#endif // _TEST_H_

In this case the generator produces TestProject.cbp w/o any header file. Let's see how can this be fixed.

Update2 : Well, I have some bad news for you. Unfortunately the code chunk of the CodeBlocks generator responsible for searching and adding header files is too simple to correctly handle your case. Here's the comment from Source/cmExtraCodeBlocksGenerator.cxx from CMake sources:

// The following loop tries to add header files matching to implementation
// files to the project. It does that by iterating over all source files,
// replacing the file name extension with ".h" and checks whether such a
// file exists. If it does, it is inserted into the map of files.
// A very similar version of that code exists also in the kdevelop
// project generator.

So as you may see this approach is useful only if test.cpp and test.h reside side by side, in one directory. So it's the direction for further improvements. I could suggest to contact the person from this forum thread http://forums.codeblocks.org/index.php?topic=16892.0 and discuss how the situation can be improved. Maybe it's reasonable to involve gcc -MM -I<include directories> test.cpp invocation upon the project generation but this method is expensive and may easily break if the code can't be compiled at the moment.



标签: cmake