Vijay D'Silva
Vijay D'Silva

Reputation: 33

Linking a local JSONCpp install with CMake and ExternalProject_Add

I'm trying to use CMake to build a project that uses JSONCpp. I want to download JSONCpp, compile it locally and link to it. The project structure has the CMake files for third-party directories in a separate location. I get two errors.

  1. The CMake process attempts to install a file globally and I am not able to identify the CMake variable to set to install this locally or not to install it at all.
  2. When I run make, the linker cannot find libjsoncpp even though I tried to set all the variables I could to point it in the right direction.

Does anyone know how to turn off the attempt at global install? How do I point the linker to the right location in a portable manner?

The project structure I'm using is :

./jsoncpp_build_test.cc
./third_party/CMakeLists.txt.jsoncpp
./third_party/CMakeLists.txt
./CMakeLists.txt

The source file, jsoncpp_build_test is:

#include <iostream>
#include "json/json.h"
int main(int argc, char **argv) {
  Json::Value json_doc;
  std::cout << json_doc.asString() << std::endl;
  return 0;
}

The main ./CMakeLists.txt file.

project(jsontest CXX C)
cmake_minimum_required(VERSION 2.8.12)

add_subdirectory(third_party)
set(jsoncpp_lib_dir ${CMAKE_BINARY_DIR}/jsoncpp-build/src/lib_json)
set(jsoncpp_src_dir ${CMAKE_BINARY_DIR}/jsoncpp-src/include)
add_executable(jsoncpp_build_test "jsoncpp_build_test.cc")
target_include_directories(jsoncpp_build_test PRIVATE  ${jsoncpp_src_dir})
target_include_directories(jsoncpp_build_test PRIVATE ${jsoncpp_lib_dir})
target_link_libraries(jsoncpp_build_test jsoncpp)

The third_party/CMakeLists.txt file. I was trying to download JSONCpp and install it to avoid the user having to run multiple build-related commands.

configure_file(CMakeLists.txt.jsoncpp
    jsoncpp/CMakeLists.txt)
set(jsoncpp_work_dir "${CMAKE_BINARY_DIR}/third_party/jsoncpp")
set(jsoncpp_build_dir "${CMAKE_BINARY_DIR}/jsoncpp-build")
set(jsoncpp_lib_dir "${CMAKE_BINARY_DIR}/jsoncpp-lib")
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
    WORKING_DIRECTORY ${jsoncpp_work_dir} )
message(STATUS "INSTALL DIR is ${CMAKE_INSTALL_PREFIX}")
set(CMAKE_INSTALL_COMPONENT "${CMAKE_BINARY_DIR}/jsoncpp-lib")
message(STATUS "INSTALL COMPONENT is ${CMAKE_INSTALL_COMPONENT}")
execute_process(COMMAND ${CMAKE_COMMAND} --build .
    WORKING_DIRECTORY ${jsoncpp_work_dir} )

Finally, the third_party/CMakeLists.txt.json file which uses the ExternalProject_Add module.

cmake_minimum_required(VERSION 2.8.12)
project(jsoncpp-download NONE)
set(jsoncpp_install_prefix "${CMAKE_BINARY_DIR}/jsoncpp-lib")
set(CMAKE_INSTALL_COMPONENT "${jsoncpp_install_prefix}")
include(ExternalProject)
ExternalProject_Add(jsoncpp-parser
  GIT_REPOSITORY    https://github.com/open-source-parsers/jsoncpp.git
  GIT_TAG           master
  SOURCE_DIR        "${CMAKE_BINARY_DIR}/jsoncpp-src"
  BINARY_DIR        "${CMAKE_BINARY_DIR}/jsoncpp-build"
  INSTALL_DIR       "${CMAKE_BINARY_DIR}/jsoncpp-lib"
  CMAKE_ARGS        "-DCMAKE_INSTALL_PREFIX=${jsoncpp_install_prefix}"
)

The result of cd build && cmake ../ is below. I don't want to install jsoncpp globally though.

-- The CXX compiler identification is GNU 4.8.4
-- The C compiler identification is GNU 4.8.4
...
[100%] Built target jsoncpp_test
[ 87%] Performing install step for 'jsoncpp-parser'
[ 50%] Built target jsoncpp_lib_static
[ 66%] Built target jsontestrunner_exe
[100%] Built target jsoncpp_test
Install the project...
-- Install configuration: "Release"
CMake Error at cmake_install.cmake:44 (FILE):
  file cannot create directory: /lib/pkgconfig.  Maybe need administrative privileges.
make[3]: *** [install] Error 1
make[2]: *** [jsoncpp-parser-prefix/src/jsoncpp-parser-stamp/jsoncpp-parser-install] Error 2
make[1]: *** [CMakeFiles/jsoncpp-parser.dir/all] Error 2
make: *** [all] Error 2
-- Configuring done
-- Generating done
-- Build files have been written to: /tmp/cmake_test/build

The result of make is:

Scanning dependencies of target jsoncpp_build_test
[100%] Building CXX object
CMakeFiles/jsoncpp_build_test.dir/jsoncpp_build_test.cc.o
Linking CXX executable jsoncpp_build_test
/usr/bin/ld: cannot find -ljsoncpp
collect2: error: ld returned 1 exit status
make[2]: *** [jsoncpp_build_test] Error 1
make[1]: *** [CMakeFiles/jsoncpp_build_test.dir/all] Error 2
make: *** [all] Error 2

Upvotes: 3

Views: 2931

Answers (1)

Tsyvarev
Tsyvarev

Reputation: 66061

By default, command configure_file replaces all occurences of ${var_name} with value of corresponded variable.

So it replaces ${jsoncpp_install_prefix} with empty string, because there is no jsoncpp_install_prefix variable in the caller's context.

If you want to replace only some variable's references, you may use @ONLY option of the command, so only @var_name@ occurence will be replaces, but ${var_name} will remains unchanged:

third_party/CMakeLists.txt.json:

cmake_minimum_required(VERSION 2.8.12)
project(jsoncpp-download NONE)
# This reference will be replaced when configured
set(jsoncpp_install_prefix "@CMAKE_BINARY_DIR@/jsoncpp-lib") 
# But this reference remains unchanged, until resulted CMakeLists.txt will be interpreted.
set(CMAKE_INSTALL_COMPONENT "${jsoncpp_install_prefix}")
...

third_party/CMakeLists.txt:

configure_file(CMakeLists.txt.json
    jsoncpp/CMakeLists.txt
    @ONLY)

Upvotes: 1

Related Questions