4

C++ で記述された json パーサーである jsoncpp に依存するライブラリがあります。現時点では、jsoncpp は安定しており、頻繁に更新されることはありません。また、パブリック ドメインにリリースされています。現在、ライブラリを構築するために、SCons と Python に依存しています。これは機能しますが、一部のユーザーにとっては迷惑です。jsoncpp、SCons、Python をダウンロードしてからライブラリを自分でビルドするのではなく、コードをプロジェクトに直接含めて、すべてを一緒にビルドすることができます。ただし、これによりいくつかの問題が発生します。

主に、jsoncpp コードをライブラリに含めると、ライブラリには jsoncpp シンボルが含まれます。ユーザーが既に jsoncpp に依存しているライブラリに私のライブラリを埋め込もうとすると、シンボルの競合が発生します。この問題に対処する正しい方法は何ですか? たとえば、ライブラリと jsoncpp を別々にコンパイルして、両方のライブラリを配布できます。ユーザーが既に jsoncpp を持っている場合は、独自のバージョンをリンクできます。別の方法として、jsoncpp コードを変更して、すべてを新しい名前空間にプッシュすることもできますが、これは面倒です。

それが役立つ場合、私はすべてを CMake でビルドします。これを処理するための CMake のトリックがあれば、それが最善です。


編集

Fraserの提案に基づいて、私は次のことを持っています。

$ 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)

基本的に、jsoncpp をビルド ディレクトリにローカルにコンパイルしてインストールするために、CMake の ExternalProject スクリプトを使用します。ライブラリがインストールされたら、実行可能ファイルをライブラリにリンクできます。jsoncpp には CMakeLists.txt が含まれていないため、パッチ手順を使用して、適切な CMake スクリプトを jsoncpp ソース構造に挿入します。より洗練されたビルド スクリプトでは、このビルド プロシージャを使用するか、ユーザーにライブラリを直接指定させるかを選択できます。

いずれにせよ、おそらく他の誰かがこれを便利だと思うでしょう。一部のユーザーのビルド設定を簡素化しますが、すべてのシンボルを一部のメガ ライブラリにバンドルするわけではありません。

4

1 に答える 1

2

すべてのユーザーを満足させたい場合 (私は知っています - 不可能です!)、optionfor each 依存関係を追加できますoption(BuildJsonCpp)

がの場合はoption依存ON関係を構築し、それ以外の場合は find_libraryandfind_pathまたはを使用して組み込みますfind_package

ソースを含めるのではなく、依存関係を構築するには、ExternalProjectCMake モジュールを検討できます。このモジュールは、外部プロジェクトのダウンロード、構成、ビルド、およびインストールに使用され、外部プロジェクトをソース ツリーではなくビルド ツリーに完全に含めることができます。

これにより、プロジェクトに独自のソース ファイルのみを保持できるため、特に依存関係を構築したくないユーザーにとっては、プロジェクトがより小さく、より適切になります。

これにより、CMake ファイルが少し複雑になり、保守が難しくなりますが、ビルド システムをより柔軟にしたい場合は、その代償を払う必要があると思います。

于 2013-07-23T23:55:41.813 に答える