Bootstrapping a vcpkg-based mission in Linux and Home windows with idiomatic cmake

[ad_1]

This weblog is an element #2 within the sequence of making an attempt out totally different package deal managers to bootstrap a cmake mission. Checkout half #1 about Bootstrapping a vcpkg-based cmake mission in Visible Studio. Half #3 is about bootstrapping Hunter-based cmake mission in Linux and Visible Studio. The cmake code within the earlier put up works effectively on Linux too. In any case, each cmake and vcpkg are designed for cross-platform construct administration. So what’s new right here?

This time round we’ll get the identical mission off the bottom in each Linux and Home windows with cmake correct. Final time, the cmake script CMakeLists.txt felt like a poorly written bash script. Since that blogpost, I acquired lots of suggestions.

Suggestions from Carlos ORyan (Google) varieties the idea of this weblog put up. It might be extra correct to say that I am downright stealing the cmake-vcpkg integration scripts he shared with me. They’re open-source and accessible at google-cloud-cpp/tremendous. I’ve copied them almost verbatim to my vcpkg_cmake_blog department for ease of use and long run stability of the hyperlinks. Thanks Carlos!

The target is identical: bootstrap a vcpkg-based cmake mission. The mechanics are rather more subtle and really feel idiomatic cmake. Let’s get began.

Cmake Undertaking Construction

vcpkg_test
├── cmake
│   ├── AutoVcpkg.cmake
│   └── VcpkgBootstrap.cmake
├── CMakeLists.txt
├── embody
│   └── driver.h
├── src
│   └── driver.cpp
└── take a look at
    └── driver_test.cpp

There’re two extra information underneath the cmake listing. These are cmake scripts designed to obtain, set up, configure vcpkg situations in each Linux and Home windows. In addition they expose appropriate cmake operate to be used to make use of in CMakeLists.txt. This integration is way nicer (but in addition complicated).

The CMakeLists.txt appears to be like as follows.

cmake_minimum_required (VERSION 3.12)
set(MY_PROJECT_DEPENDENCIES boost-core boost-optional boost-filesystem) 

# This part of cmake is utilizing AutoVcpkg to obtain, set up, and configure vcpkg.
listing(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake")
embody(AutoVcpkg)
vcpkg_install(${MY_PROJECT_DEPENDENCIES})
message(STATUS "CMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}")

# The CMakeLists from this level on is identical as that of half 1. 
mission (vcpkg_test CXX)
set(CMAKE_CXX_STANDARD 17)
find_package(Enhance 1.67 REQUIRED COMPONENTS filesystem)

add_executable(driver src/driver.cpp)
target_include_directories(driver PUBLIC ${Boost_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/embody )
target_link_libraries(driver ${Boost_LIBRARIES})

enable_testing()
embody(CTest)
add_executable(driver_test ${PROJECT_SOURCE_DIR}/take a look at/driver_test.cpp)
add_test(NAME driver COMMAND driver_test)

find_package finds and masses settings from an exterior mission (package deal). Boost_FOUND might be set to point whether or not the Enhance package deal was discovered. add_executable merely provides a goal named driver to be constructed from the sources (src/driver.cpp). The Enhance library dependencies are specified subsequent for the driver goal. First, a set of are directories are specified. Subsequent, a set of libraries are specified. Notice that boost-filesystem should be linked to driver program. Therefore, target_link_libraries is important. The variables Boost_INCLUDE_DIRS, Boost_LIBRARIES are set by find_package (solely upon success).

vcpkg_install

This is the total code of AutoVcpkg.cmake. This is the github department vcpkg_cmake_blog_idiomatic.

We’re together with the information underneath cmake listing as “modules” and easily invoking them utilizing vcpkg_install. The code is generally self-explanatory. If you’re new to cmake, you might need to stare at it for some time although.

/>
The vcpkg-download is a separate cmake mission. The CMakeLists.txt for this mission is created whereas producing the construct information for the motive force mission. I.e., It permits each mission to bootstrap it is personal vcpkg repository. This will or is probably not fascinating. For smaller mission it is perhaps an overkill. For big tasks the place controlling the precise library model separate from vcpkg repository HEAD is fascinating, one may need a devoted vcpkg occasion. This is the ExternalProject vcpkg_download.

cmake_minimum_required(VERSION 3.12)
mission(vcpkg-download)

embody(ExternalProject)
ExternalProject_Add(vcpkg
            GIT_REPOSITORY @AUTO_VCPKG_GIT_REPOSITORY@
            # GIT_TAG 52870c7595a63ade069ae51d5f4ee3a85fe4123f # TODO: Debug this 
            GIT_SHALLOW ON
            SOURCE_DIR @AUTO_VCPKG_ROOT@
            PATCH_COMMAND ""
            CONFIGURE_COMMAND  ""
            BUILD_COMMAND ""
            INSTALL_COMMAND ""
            LOG_DOWNLOAD ON
            LOG_CONFIGURE ON
            LOG_INSTALL ON)

So as a substitute of merely forking off and launching git clone straight from cmake, this exterior mission permits a plethora of choices and configure the obtain step.

The vcpkg_download operate spits out and runs this mission (with one other invocation of cmake) provided that wanted. I ended up passing further flags to cmake on Home windows. Having to cross further flags like CMAKE_EXE_LINKER_FLAGS, CMAKE_C_COMPILER, and CMAKE_CXX_COMPILER (from mother or father to the nested invocation of cmake) signifies that cmake integration with Visible Studio continues to be tough on the sides. This is a snippet.

operate (vcpkg_download)
    if (DEFINED AUTO_VCPKG_ROOT)
        return()
    endif ()
    set(AUTO_VCPKG_ROOT "${CMAKE_BINARY_DIR}/vcpkg")
    # Generate the vcpkg_download mission if mandatory.
    file(WRITE "${CMAKE_BINARY_DIR}/vcpkg-download/CMakeLists.txt" "${vcpkg_download_contents}")
    if(WIN32)
      get_filename_component(VC_COMPILER_PATH ${CMAKE_C_COMPILER} DIRECTORY)
      set(VCRT_LIB_PATH "${VC_COMPILER_PATH}/../../../lib/x86")
      execute_process(COMMAND "${CMAKE_COMMAND}"
              "-H${CMAKE_BINARY_DIR}/vcpkg-download"
              "-B${CMAKE_BINARY_DIR}/vcpkg-download"
              "-DCMAKE_C_COMPILER:FILEPATH=${CMAKE_C_COMPILER}"
              "-DCMAKE_CXX_COMPILER:FILEPATH=${CMAKE_CXX_COMPILER}"
              "-DCMAKE_EXE_LINKER_FLAGS=/LIBPATH:"${VCRT_LIB_PATH}"")
      execute_process(COMMAND "${CMAKE_COMMAND}"
              "--build" "${CMAKE_BINARY_DIR}/vcpkg-download")
    else()
      # Linux right here.
    endif()

If the earlier step doesn’t achieve constructing vcpkg efficiently (i.e., if AUTO_VCPKG_EXECUTABLE is undefined), there’s plan B. The plan B is to do just about fork off a baby cmake course of and run vcpkg bootstrap.sh or bootstrap.bat straight. We noticed a quite simple model of it in half #1.

operate (vcpkg_bootstrap)
    find_program(AUTO_VCPKG_EXECUTABLE vcpkg PATHS ${AUTO_VCPKG_ROOT})
    if (NOT AUTO_VCPKG_EXECUTABLE)
        execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_LIST_DIR}/cmake/VcpkgBootstrap.cmake" "${AUTO_VCPKG_ROOT}")
        execute_process(COMMAND ${CMAKE_COMMAND} -P "${AUTO_VCPKG_ROOT}/VcpkgBootstrap.cmake"
                WORKING_DIRECTORY ${AUTO_VCPKG_ROOT})
    endif ()
endfunction ()

###### VcpkgBootstrap.cmake file
find_program(VCPKG_EXECUTABLE
        vcpkg PATHS "${CMAKE_CURRENT_LIST_DIR}")
if (NOT VCPKG_EXECUTABLE)
    if (WIN32)
        execute_process(COMMAND "${CMAKE_CURRENT_LIST_DIR}/bootstrap-vcpkg.bat"
                WORKING_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}")
    else ()
        execute_process(COMMAND  "${CMAKE_CURRENT_LIST_DIR}/bootstrap-vcpkg.sh"
                WORKING_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}")
    endif ()
endif ()

At this level we have coated the gist. There are lots of new issues I discovered about cmake.

The principle variations between half #1 and this cmake mission are the next.

  1. vcpkg is cloned from the github repository, compiled, and bootstrapped within the cmake binary listing. The listing you utilize for out-of-source builds (e.g., construct). Beforehand, vcpkg is cloned, compiled, and bootstrapped in $ENV{HOMEDRIVE}$ENV{HOMEPATH}/vcpkg_cpptruths
  2. The vcpkg-download mission is an actual cmake mission that generates a Makefile for bootstrapping vcpkg. On Home windows, it generates an answer file underneath $ENV{HOMEDRIVE}$ENV{HOMEPATH}CMakeBuilds...buildx86-Debugvcpkg-download. Issues are actually meta at this level. cmake ExternalProject is used for that. Some tweaks in execute_process have been essential to cross the suitable ${CMAKE_EXE_LINKER_FLAGS}to construct vcpkg with Visible Studio.

The tasks appears to include some meta targets which are unrelated to the principle “driver” mission. This is the way it appears to be like like.

Observations

There are a few issues vcpkg.cmake might make the expertise higher.

  1. GIT_TAG … merely didn’t work for me in ExternalProject_Add. Cloning a particular tag/department/commit hash of vcpkg is essential for reproducible builds. Btw, Why aren’t there any official releases of vcpkg? There’s not a single tag as of this writing.
  2. The approach is that this put up is decrease degree however feels rather more well-integrated. Nonetheless, the tip impact is identical. Unsure if it is well worth the elevated complexity. Particularly as a result of I needed to overcome vcpkg construct error “LINK : deadly error LNK1104: can not open file ‘MSVCRTD.lib'” that didn’t occur in half #1. The ensuing Visible Studio mission has some cruft too.

[ad_2]

Leave a Comment

Your email address will not be published. Required fields are marked *