2014-12-27 53 views
3

我有一個用C++編寫的項目,我正在使用cmake來構建它。 該項目有許多子項目,其中一個是其他子項目所需的lib。 我可以編譯和使用 add_library移動。所以到構建目錄,並 INSTALL(靶向...)cmake install(FILES ...)似乎沒有工作

但是我還需要的lib的頭文件的包含目錄下安裝建立目錄。 我使用安裝(文件...)來做到這一點,但它似乎根本沒有做到這一點。

爲了演示,我創建通過qtcreator一個測試項目,

& ls test 
CMakeLists.txt empty.hh main.cpp 

$ cat test/CMakeLists.txt 
project(test) 
cmake_minimum_required(VERSION 2.8) 
install(FILES empty.hh DESTINATION include) 
aux_source_directory(. SRC_LIST) 
add_executable(${PROJECT_NAME} ${SRC_LIST}) 

$ cat test/main.cpp 
#include 

using namespace std; 

int main() 
{ 
cout << "Hello World!" << endl; 
return 0; 
} 

$ cat test/empty.hh 
#ifndef EMPTY_HH 
#define EMPTY_HH 

#endif // EMPTY_HH 

If the files under "test" qtcreator will compile (by default) the files to test-build. 
$ ls test-build/ 
CMakeCache.txt CMakeFiles Makefile cmake_install.cmake test test.cbp 
$ ./test-build/test 
Hello World! 

正如你所看到的,沒有包含目錄或文件empty.hh。 也試圖使用

install(FILES empty.hh DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) 

但仍然看不到頭文件。

$ cmake --help 
cmake version 2.8.12 

如果您有任何想法,請讓我知道。

回答

8

使用install命令在構建時移動文件通常是不好的方法。該命令旨在用於設置在用戶執行make install或同等操作時將安裝的文件和目標。由於你沒有運行make install,我預計這就是爲什麼install(FILES ...)命令似乎不起作用。

你有一些稍微不同的方法來完成這項工作。

我推薦不是如果您不需要移動標題。假設你的庫稱爲MyLib,那麼你可以通過target_include_directories使這些頭可作爲MyLib目標的一部分:

target_include_directories(MyLib PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}") 

這意味着,如果有一個相關的目標,如MyExe

target_link_libraries(MyExe MyLib) 

則自動有權訪問MyLib的源代碼目錄。


如果庫的目錄結構不適合將API頭與其餘源和頭分開,那麼這可能不太理想。假設MyLib由以下文件組成:my_lib.cpp,my_lib_api.hh(API標頭 - 用於其他項目)和my_lib_detail.hh(不包含在其他項目中)。一個理想的結構將保持API標題與其餘的不同,例如,

/my_lib 
    - CMakeLists.txt 
    - src/ 
     - my_lib.cpp 
     - my_lib_detail.hh 
    - include/ 
     - my_lib/ 
      - my_lib_api.hh 

有了這個結構,你可以只指定

target_include_directories(MyLib PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" 
           PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src") 

MyLib來源將能夠遏制#include "my_lib_detail.hh"#include "my_lib/my_lib_api.hh",但依賴的目標的來源只能包含#include "my_lib/my_lib_api.hh"


所以,如果MyLib剛剛平面結構或不內部接頭從API孩子們分開,你可能希望將API頭的位置複製了在構建樹,並添加到路徑致電target_include_directories。在這種情況下,如果MyLib本身不需要訪問複製的文件(只是源樹中的原始文件),則可以在調用target_include_directories時使用INTERFACE而不是PUBLIC。但是,這個問題的關鍵(並回答你的實際問題我想)是作爲配置過程(當CMake運行時)或構建過程(當運行時)的一部分複製這些文件 - 而不是作爲部分的安裝過程。

所以,讓我們假設MyLib具有上文所示的有用的目錄結構,而是是平坦的(即和的CMakeLists.txt三個源文件都在相同的目錄)。我們可以使用一個生成後命令API頭複製出來,以構建樹:

project(my_lib) 
cmake_minimum_required(VERSION 2.8.12.2) # for 'target_include_directories' 
add_library(MyLib SHARED my_lib.cpp my_lib_api.hh my_lib_detail.hh) 
target_include_directories(MyLib INTERFACE "${CMAKE_BINARY_DIR}/include" 
           PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}") 

file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/include/my_lib") 
add_custom_command(TARGET MyLib POST_BUILD 
    COMMAND ${CMAKE_COMMAND} -E copy_if_different 
     "${CMAKE_CURRENT_SOURCE_DIR}/my_lib_api.hh" 
     "${CMAKE_BINARY_DIR}/include/my_lib" 
    COMMENT "Copying MyLib public headers to ${CMAKE_BINARY_DIR}/include/my_lib" 
    VERBATIM) 

那麼對於MyExe的的CMakeLists.txt,你可以做:

project(my_exe) 
cmake_minimum_required(VERSION 2.8.12.2) 
add_executable(MyExe main.cpp) 
target_link_libraries(MyExe MyLib) 

# Copy MyLib.so to this build dir to allow MyExe to find it at runtime 
add_custom_command(TARGET MyExe POST_BUILD 
    COMMAND ${CMAKE_COMMAND} -E copy_if_different 
     "$<TARGET_FILE:MyLib>" 
     "$<TARGET_FILE_DIR:MyExe>" 
    VERBATIM) 


這不會像MSVC那樣工作 - 您需要處理Windows導出庫(有關更多詳細信息,請參見CMake wikiGenerateExportHeader的文檔),但它只是涉及諸如將以下內容添加到MyLib的的CMakeLists.txt:

include(GenerateExportHeader) 
generate_export_header(MyLib 
    BASE_NAME MyLib 
    EXPORT_MACRO_NAME MyLib_EXPORT 
    EXPORT_FILE_NAME "${CMAKE_BINARY_DIR}/include/my_lib/my_lib_export.hh" 
    STATIC_DEFINE MyLib_BUILT_AS_STATIC) 

如果你確實需要這樣,你必須改變INTERFACEPUBLICtarget_include_directories(MyLib ...),因爲MyLib然後將自己需要訪問生成的文件"${CMAKE_BINARY_DIR}/include/my_lib/my_lib_export.hh"

+0

嗨弗雷澤,謝謝你。不幸的是,我不能試試這個,因爲我沒有cmake 2.8.12.2。但是你的解決方案似乎很有前途,我會在稍後嘗試。在此之前,我將使用文件(COPY)將頭文件複製到所需位置。再次感謝! – czappa

+0

不用擔心 - '文件(COPY ...)'應該可以正常工作。 – Fraser