将一个项目组合到另一个项目中的方法
Methods to combine one project into another
我有一个依赖于jsoncpp的库,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源结构中。在一个更高级的构建脚本中,我们可以选择是否使用这个构建过程,或者让用户直接指定库。
无论如何,也许其他人会觉得这很有用。它简化了一些用户的构建设置,但不会将所有符号捆绑到某个大型库中。
如果你想让所有用户都满意(我知道-不可能!),你可以为每个依赖项添加一个option
,例如option(BuildJsonCpp)
。
如果option
是ON
,则构建依赖项,否则使用find_library
和find_path
或find_package
将其包含在内。
为了构建依赖关系,而不是包括源,您可以考虑ExternalProject
CMake模块。该模块用于下载、配置、构建和安装外部项目,并允许外部项目完全包含在构建树中,而不是源树中。
这将允许您在项目中只保留自己的源文件,使其更小、更相关,尤其是对于不希望构建依赖关系的用户。
这会让你的CMake文件变得更复杂,更难维护,但我想如果你想让构建系统更灵活,这就是你必须付出的代价。
- 运行同一解决方案的另一个项目的项目
- 如何有效地将(一些)项目从一个std::map移动到另一个std::map
- 是否可以将 EXE 文件作为 lib 文件链接到另一个项目?
- 从另一个动态链接库项目调用静态库函数
- 如何在QListWidget中显示QStringList的每个项目QLabel和另一个QString?
- 如何使用另一个项目命名空间?
- 如何将一个 exe 项目链接到另一个 exe 项目中的类
- 如何在我的 cmake 项目中包含另一个 cmake 项目的头文件?
- 单元测试类无法在我要测试的同一解决方案中的另一个项目中找到类
- 在 NDK 上编译两个带有 gradle 的项目,其中一个依赖于另一个的二进制文件
- 如果我尝试将对话框从一个项目移动到另一个项目,我是否需要从 rc 文件中复制 DESIGNINFO、对话框信息和AFX_
- OpenCV:文件存储操作员">>"在一个项目中工作,但不在另一个项目中工作(在同一类上)
- LNK2019与另一个工作项目具有相同属性的项目上的错误
- Qt 创建者在我将项目移动到另一个地方后仍然使用源项目
- 如何将另一个项目中用 C 编写的源代码包含在我自己的项目中,C++在 Visual Studio 中
- 如何创建一个函数,该函数可以从一个qtreewidget中删除项目并将其添加到另一个函数
- 将过滤器中的所有.cpp和.h移动到另一个项目并更正其文件夹位置
- 在另一个项目中包括继承的类时,抽象类的链接器错误
- 创建在另一个项目中定义的类对象
- 如何在不复制的情况下将C++类从一个项目重用到另一个项目