Bootstrapping a vcpkg-based cmake undertaking in Visible Studio

[ad_1]

After the final week’s 2019 Microsoft MVP Summit, I made a decision to offer Microsoft vcpkg a shot. I’ve a cmake undertaking at work and we goal Linux utilizing the Hunter bundle supervisor. So vcpkg had been on the back-burner for me.

I am focusing on a 4 half 3 half weblog collection.

  1. Bootstrapping a cmake undertaking primarily based on vcpkg in Visible Studio (this publish)
  2. Bootstrapping a cmake undertaking primarily based on vcpkg in Linux and Visible Studio with idiomatic cmake (right here)
  3. Bootstrapping a cmake undertaking primarily based on Hunter in Linux and Home windows (right here)

As of this writing I am new to vcpkg. So I apologize prematurely in case you are aggravated by noob errors. Please depart a remark when you discover one thing.

In case you desire to clone/browse a github undertaking. All contents on this blogpost can be found below cpptruths/cpp0x/vcpkg_test (department vcpkg_cmake_blog).

To start out with, I’ve a barebones C++ undertaking with almost empty driver.cpp and driver.h recordsdata. Later, I am going to add Increase core and non-compulsory as third celebration dependencies. Each are header-only. Later, we’ll add libraries requiring linking. So, let’s get began.

A barebones C++ cmake undertaking

The next is the undertaking construction of my near-empty C++ undertaking vcpkg_test

vcpkg_test
├── CMakeLists.txt
├── embrace
│   └── driver.h
├── src
│   └── driver.cpp
└── check
    └── driver_test.cpp

3 directories, 4 recordsdata

The driver.cpp and driver_test.cpp recordsdata have only a primary operate that does nothing. driver.h is empty. The CMakeLists.txt appears to be like as follows.

cmake_minimum_required (VERSION 3.12)

undertaking (vcpkg_test CXX)
set(CMAKE_CXX_STANDARD 17)

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

enable_testing()
embrace(CTest)
add_executable(driver_test ${PROJECT_SOURCE_DIR}/check/driver_test.cpp)
add_test(NAME driver COMMAND driver_test)

See the cmake tutorial if the above file is all greek. It builds two executables from the sources: driver and driver_test.

There’re some ways to construction the undertaking. On this undertaking I’ve chosen to make use of just one CMakeLists.txt to construct each the sources and the check. One might have added CMakeLists.txt in src and check sub-directories.

Open cmake Venture in Visible Studio

Visible Studio 2017+ has built-in assist for cmake initiatives. Sure, you learn that proper! You may open the folder containing the top-level CMakeLists.txt and Visible Studio will work out every thing. The loaded undertaking appears to be like very clear.

Issues was once very totally different not too way back. cmake’s native answer generator used so as to add further targets that aren’t seen within the CMakeLists.txt you wrote. I all the time questioned what magic was happening there.

/>
Visible Studio runs cmake mechanically on the CMakeLists.txt.

Venture construct and rebuild works as anticipated.

Targets driver.exe and driver_test.exe can be found within the drop-down. Here is how my loaded undertaking appears to be like like. No cruft!

So, that is how a toy C++ cmake undertaking appears to be like like. Let’s use vcpkg to handle our third-party dependencies: boost-core and boost-optional.

Including vcpkg to a cmake undertaking

Here is a vcpkg tutorial to get your cmake undertaking off the bottom in Visible Studio. Nonetheless, my aim is to create a reproducible construct with most automation when a consumer clones the undertaking listing. Maybe one thing that would run as-is on AppVeyor CI servers. So the next CMakeLists.txt expects solely Visible Studio 2017+ put in on a Home windows machine.

The script clones the vcpkg repository and bootstraps it as obligatory. We additionally change the CMAKE_TOOLCHAIN_FILE variable to level to the vcpkg occasion the script downloaded and bootstrapped. This permits cmake to find, embrace, and hyperlink packages managed by vcpkg. Right here’re the adjustments to CMakeLists.txt.

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

if(NOT DEFINED ${CMAKE_TOOLCHAIN_FILE})
  if(NOT DEFINED ENV{VCPKG_ROOT})
    if(WIN32)
      set(VCPKG_ROOT $ENV{HOMEDRIVE}$ENV{HOMEPATH}/vcpkg_cpptruths)
    else()
      set(VCPKG_ROOT $ENV{HOME}/.vcpkg_cpptruths)
    endif()
  else()
    set(VCPKG_ROOT $ENV{VCPKG_ROOT})
  endif()

  if(NOT EXISTS ${VCPKG_ROOT})
    message("Cloning vcpkg in ${VCPKG_ROOT}")
    execute_process(COMMAND git clone https://github.com/Microsoft/vcpkg.git ${VCPKG_ROOT})
    # If a reproducible construct is desired (and probably outdated libraries are # okay), uncomment the
    # following line and pin the vcpkg repository to a selected githash.
    # execute_process(COMMAND git checkout 745a0aea597771a580d0b0f4886ea1e3a94dbca6 WORKING_DIRECTORY ${VCPKG_ROOT})
  else()
    # The next command has no impact if the vcpkg repository is in a indifferent head state.
    message("Auto-updating vcpkg in ${VCPKG_ROOT}")
    execute_process(COMMAND git pull WORKING_DIRECTORY ${VCPKG_ROOT})
  endif()

  if(NOT EXISTS ${VCPKG_ROOT}/README.md)
    message(FATAL_ERROR "***** FATAL ERROR: Couldn't clone vcpkg *****")
  endif()

  if(WIN32)
    set(BOOST_INCLUDEDIR ${VCPKG_ROOT}/put in/x86-windows/embrace)
    set(VCPKG_EXEC ${VCPKG_ROOT}/vcpkg.exe)
    set(VCPKG_BOOTSTRAP ${VCPKG_ROOT}/bootstrap-vcpkg.bat)
  else()
    set(VCPKG_EXEC ${VCPKG_ROOT}/vcpkg)
    set(VCPKG_BOOTSTRAP ${VCPKG_ROOT}/bootstrap-vcpkg.sh)
  endif()

  if(NOT EXISTS ${VCPKG_EXEC})
    message("Bootstrapping vcpkg in ${VCPKG_ROOT}")
    execute_process(COMMAND ${VCPKG_BOOTSTRAP} WORKING_DIRECTORY ${VCPKG_ROOT})
  endif()

  if(NOT EXISTS ${VCPKG_EXEC})
    message(FATAL_ERROR "***** FATAL ERROR: Couldn't bootstrap vcpkg *****")
  endif()

  set(CMAKE_TOOLCHAIN_FILE ${VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake CACHE STRING "")

  message(STATUS "***** Checking undertaking third celebration dependencies in ${VCPKG_ROOT} *****")
  execute_process(COMMAND ${VCPKG_EXEC} set up ${MY_PROJECT_DEPENDENCIES} WORKING_DIRECTORY ${VCPKG_ROOT})
endif()

If every thing goes properly, the cmake script clones vcpkg repository below $ENV{HOMEDRIVE}$ENV{HOMEPATH}/vcpkg_cpptruths and bootstraps it (i.e., there’re no pre-installed packages). Any more it is going to mechanically use the CMAKE_TOOLCHAIN_FILE from this listing. In fact, you possibly can override the CMAKE_TOOLCHAIN_FILE on the command immediate to level to a unique vcpkg occasion all totally different toolchain altogether. Additionally, be at liberty to alter the trail vcpkg_cpptruths to one thing you want.

Managing third-party dependencies with vcpkg

Now’s the time so as to add the increase dependencies. Three steps are wanted.

  1. Write code that makes use of boost-core and boost-optional
  2. Instruct vcpkg to obtain and set up boost-core and boost-optional
  3. Replace CMakeLists.txt with the appropriate dependencies

Here is my check code that makes use of boost-core and boost-optional.

#embrace <iostream>
#embrace <cstdlib>
#embrace <ctime>
#embrace <cmath>
#embrace <typeinfo>

#embrace "increase/core/demangle.hpp"
#embrace "increase/filesystem.hpp"
#embrace "driver.h"

void check_exists(const char *filename) {
  utilizing namespace increase::filesystem;
  path p(filename);

  if (exists(p)) {   // does p truly exist?
          if (is_regular_file(p))        // is p a daily file?
                  std::cout << p << " measurement is " << file_size(p) << 'n';
          else if (is_directory(p))      // is p a listing?
                std::cout << p << " is a directoryn";
        else
                std::cout << p << " exists, however is neither a daily file nor a directoryn";
  }
  else
          std::cout << p << " doesn't existn";
}

int primary() {  
  std::srand(static_cast<unsigned int>(std::time(0)));  
  increase::non-compulsory<int> i = Generator::get_even_random_number();
  if (i) {
    std::cout << std::sqrt(static_cast<float>(*i)) << "n";
    std::cout << increase::core::demangle(typeid(increase::non-compulsory<int>).title()) << "n";
  }
  check_exists("driver");
}

For #2, you may open a shell and run vcpkg set up boost-core boost-optional boost-filesystem. It is easy. Nonetheless, I need a reproducible computerized construct setup. So I’ll have cmake run the identical vcpkg command and set up the dependencies it may use later.

set(MY_PROJECT_DEPENDENCIES boost-core boost-optional boost-filesystem)
message(STATUS "***** Checking undertaking third celebration dependencies in ${VCPKG_ROOT} *****")
execute_process(COMMAND ${VCPKG_ROOT}/vcpkg.exe set up ${MY_PROJECT_DEPENDENCIES} WORKING_DIRECTORY ${VCPKG_ROOT})

The execute_process command will get the job achieved. Nonetheless, I am unsure, if there’s a greater to do the identical factor. Check out half #2 with idiomatic cmake. Is there a higher-level cmake operate(s) in vcpkg.cmake that will set up the libraries within the vcpkg occasion (pointed by the CMAKE_TOOLCHAIN_FILE).

Saving the file CMakeLists.txt in Visible Studio runs it and installs the packages in ${MY_PROJECT_DEPENDENCIES}.

Now we replace CMakeLists.txt to search for increase libraries. This half step is platform and package-manger impartial.

find_package(Increase 1.67 REQUIRED COMPONENTS filesystem)
add_executable(driver src/driver.cpp)
target_include_directories(driver PUBLIC ${Boost_INCLUDE_DIR} ${PROJECT_SOURCE_DIR}/embrace)
target_link_libraries(driver ${Boost_LIBRARIES})

find_package finds and hundreds settings from an exterior undertaking (bundle). Boost_FOUND can be set to point whether or not the Increase bundle was discovered. add_executable merely provides a goal named driver to be constructed from the sources (src/driver.cpp). The Increase library dependencies are specified subsequent for the driver goal. First, a set of are directories are specified. Subsequent, a set of libraries are specified. Observe that boost-filesystem have to be linked to driver program. Therefore, target_link_libraries is crucial. The variables Boost_INCLUDE_DIR, Boost_LIBRARIES are set by find_package (solely upon success).

You might have to regenerate the cmake cache because the CMAKE_TOOLCHAIN_FILE has been up to date. You are able to do that by right-clicking on CMakeLists.txt.

At this level the code builds and runs cleanly for me. No squiggles.

Observations

Some issues I famous would make the expertise nicer in Visible Studio 2019.

  1. The Open Venture/Resolution dialog field didn’t present CMakeLists.txt below “All Venture Information” drop down. First-class assist ought to make the expertise seamless.
  2. If vcpkg is built-in with Visible Studio such that libraries get put in in the appropriate vcpkg occasion, that will be nice.
  3. It could be good to have cmake capabilities in vcpkg.cmake that will set up libraries within the vcpkg occasion. I obtained responses from a number of individuals who had some floor work right here.
    1. See Bundle Supervisor Supervisor (pmm) talked about on reddit/r/cpp.
    2. Google-cloud-cpp/tremendous undertaking makes use of cmake performance corresponding to ExternalProject_Add and different mates to bootstrap a vcpkg occasion.
  4. After updating CMakeLists.txt, the output of cmake shouldn’t be displayed within the IDE right-away. It takes an excellent minute and it seems like Visible Studio is caught. Looks like cmake doesn’t flush output to the IDE window right-away.

[ad_2]

Leave a Comment

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