2013-07-23 153 views
4

我有一个依赖于jsoncpp的库,它是用C++编写的json解析器。目前,jsoncpp很稳定,不会经常更新。它也被释放到公共领域。现在,为了构建这个库,SCons和Python依赖于它,但这对我的一些用户来说是一个烦恼。而不是让他们下载jsoncpp,SCons,Python,然后自己构建库,我可以直接将代码包含到我的项目中,并将所有内容一起构建。但是,这会导致一些问题。将一个项目合并到另一个项目的方法

首先,如果我将jsoncpp代码包含到我的库中,那么我的库包含jsoncpp符号。如果用户试图将我的库嵌入已经依赖于jsoncpp的库中,则会出现符号冲突。处理这个问题的正确方法是什么?例如,我可以分别编译我的库和jsoncpp并分发这两个库。如果用户已经拥有jsoncpp,他们可以链接自己的版本。或者,我可以修改jsoncpp代码并将所有内容都推送到新的名称空间中,但这看起来很麻烦。

如果有帮助,我在CMake中构建所有东西,所以如果有一个用于处理这个问题的CMake技巧,那最好。


编辑

基于弗雷泽的建议,我有以下。

$ find . 
. 
./build 
./build/jsoncpp-src-0.6.0-rc2.tar.gz 
./src 
./src/cpp 
./src/cpp/hello.cpp 
./src/cpp/CMakeLists.txt 
./src/thirdparty 
./src/thirdparty/jsoncpp 
./src/thirdparty/jsoncpp/CMakeLists.txt 
./src/thirdparty/CMakeLists.txt 
./src/CMakeLists.txt 

$ cat ./src/cpp/hello.cpp 
#include <cstdlib> 
#include <iostream> 
#include <fstream> 
#include <iomanip> 
#include "json/json.h" 

// Parses a JSON file and returns the root 
void parse(const std::string& fname,Json::Value& root) { 
    // Read in the input file 
    Json::Reader reader; 
    std::ifstream file(fname.c_str(),std::ifstream::in); 
    bool parsingSuccessful = reader.parse(file, root, true); 
    if (!parsingSuccessful) { 
     std::cerr << "Failed to parse the optimization parameter " 
      "file: " << reader.getFormattedErrorMessages() << std::endl; 
     exit(EXIT_FAILURE); 
    } 

    // Close everything out 
    file.close(); 
} 


int main(int argc,char* argv[]) { 
    // Make sure we have the correct number of arguments 
    if(argc!=2) { 
     std::cout << "hello <json>" << std::endl; 
     return EXIT_FAILURE; 
    } 

    // Parse the JSON files 
    Json::Value root; 
    parse(argv[1],root); 

    // Get the hello string 
    std::string hello = root["Hello"].get("Message","Hello World!").asString(); 

    // Tell everyone 
    std::cout << hello << std::endl; 

    return EXIT_SUCCESS; 
} 

$ cat ./src/cpp/CMakeLists.txt 
project(hello) 
cmake_minimum_required(VERSION 2.8.9) 
enable_language(CXX) 

# Set the location of jsoncpp 
find_library(JSONCPP_LIBRARY 
    NAMES json libjson 
    PATHS ${CMAKE_BINARY_DIR}/installed/lib) 
set(JSONCPP_LIBRARIES ${JSONCPP_LIBRARY}) 
set(JSONCPP_INCLUDE_DIRS ${CMAKE_BINARY_DIR}/installed/include) 

# Locate the headers 
include_directories(${JSONCPP_INCLUDE_DIRS}) 

# Build the executable 
add_executable(hello hello.cpp) 

# Link jsoncpp 
target_link_libraries(hello ${JSONCPP_LIBRARIES}) 

$ cat ./src/thirdparty/jsoncpp/CMakeLists.txt 
project(jsoncpp) 
cmake_minimum_required(VERSION 2.8.9) 
enable_language(CXX) 

# Set the source file prefix 
set(source_prefix ${CMAKE_CURRENT_SOURCE_DIR}/src/lib_json/) 

# Save the include directory 
set(JSONCPP_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIRI}/include) 

# Grab all the sources for the library 
set(jsoncpp_srcs 
    "${source_prefix}/json_reader.cpp" 
    "${source_prefix}/json_value.cpp" 
    "${source_prefix}/json_writer.cpp" 
) 

# Locate the headers 
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) 

# Compile everything 
set(CMAKE_POSITION_INDEPENDENT_CODE ON) 
add_library(jsoncpp_object OBJECT ${jsoncpp_srcs}) 
add_library(jsoncpp_static STATIC $<TARGET_OBJECTS:jsoncpp_object>) 
add_library(jsoncpp_shared SHARED $<TARGET_OBJECTS:jsoncpp_object>) 
set_target_properties(jsoncpp_shared jsoncpp_static 
    PROPERTIES OUTPUT_NAME json) 

# Install the libraries and headers 
install(TARGETS jsoncpp_static jsoncpp_shared DESTINATION lib) 
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/json DESTINATION include) 

$ cat ./src/thirdparty/CMakeLists.txt 
project(third_party_libraries) 
cmake_minimum_required(VERSION 2.8.9) 

# Build jsoncpp 
include(ExternalProject) 
ExternalProject_Add(
    JsonCpp 
    URL ${CMAKE_BINARY_DIR}/jsoncpp-src-0.6.0-rc2.tar.gz 
    URL_MD5 363e2f4cbd3aeb63bf4e571f377400fb 
    PATCH_COMMAND ${CMAKE_COMMAND} -E copy 
     "${CMAKE_CURRENT_SOURCE_DIR}/jsoncpp/CMakeLists.txt" 
     CMakeLists.txt 
    CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_BINARY_DIR}/installed 
) 

$ cat ./src/CMakeLists.txt 
project(hello_example) 
cmake_minimum_required(VERSION 2.8.9) 

# First, build our TPLs 
add_subdirectory(thirdparty) 

# Then, build our target 
add_subdirectory(cpp) 

基本上,我们使用的CMake的ExternalProject脚本来编译和本地安装jsoncpp到构建目录。一旦安装了库,我们可以将我们的可执行文件链接到它。由于jsoncpp不包含CMakeLists.txt,因此我们使用修补程序将适当的CMake脚本插入到jsoncpp源结构中。在更好的构建脚本中,我们可以选择是否使用此构建过程,或者让用户直接指定库。

无论如何,也许别人会觉得这很有用。它简化了某些用户的构建设置,但不会将所有符号捆绑到某个超级库中。

回答

2

如果您想尝试并保持所有用户的快乐(我知道 - 不可能!),您可以为每个依赖添加option,例如, option(BuildJsonCpp)

如果optionON,你建立的依赖,否则它包括使用find_libraryfind_pathfind_package

对于构建依赖关系,而不是包括源,可以考虑使用ExternalProject CMake模块。此模块用于下载,配置,构建和安装外部项目,并允许将外部项目完全包含在您的构建树中 - 而不是您的源代码树。

这将允许您在项目中保留自己的源文件,使其更小,更相关 - 尤其对于不希望构建依赖关系的用户。

这会让你的CMake文件变得更加复杂和难以维护,但是我想如果你想让构建系统更加灵活,你就必须付出代价。

相关问题