build,test: add support for Vcpkg and CPM package managers

Gabriel Ferreira 2023-07-27 00:44:50 -03:00
parent 8c50a77521
commit e7246b4e78
9 changed files with 417 additions and 1 deletions

1
.gitignore vendored
View File

@ -48,6 +48,7 @@ cmake-build-debug/
cmake-build-relwithdebinfo/
cmake-build-minsizerel/
cmake-build-release/
vcpkg/
.vs/

View File

@ -55,6 +55,7 @@ option(NS3_NETANIM "Build netanim" OFF)
# other options
option(NS3_ENABLE_BUILD_VERSION "Embed version info into libraries" OFF)
option(NS3_CCACHE "Use Ccache to speed up recompilation" ON)
option(NS3_CPM "Enable the CPM C++ library manager support" OFF)
option(NS3_FAST_LINKERS "Use Mold or LLD to speed up linking if available" ON)
option(NS3_FETCH_OPTIONAL_COMPONENTS
"Fetch Brite, Click and Openflow dependencies" OFF
@ -82,6 +83,7 @@ option(NS3_EIGEN "Build with Eigen support" ON)
option(NS3_STATIC "Build a static ns-3 library and link it against executables"
OFF
)
option(NS3_VCPKG "Enable the Vcpkg C++ library manager support" OFF)
option(NS3_VERBOSE "Print additional build system messages" OFF)
option(NS3_VISUALIZER "Build visualizer module" ON)
option(NS3_WARNINGS "Enable compiler warnings" ON)

View File

@ -191,9 +191,29 @@ function(build_lib)
# include directories, allowing consumers of this module to include and link
# the 3rd-party code with no additional setup
get_target_includes(${lib${BLIB_LIBNAME}} exported_include_directories)
string(REPLACE "-I" "" exported_include_directories
"${exported_include_directories}"
)
# include directories prefixed in the source or binary directory need to be
# treated differently
set(new_exported_include_directories)
foreach(directory ${exported_include_directories})
string(FIND "${directory}" "${PROJECT_SOURCE_DIR}" is_prefixed_in_subdir)
if(${is_prefixed_in_subdir} GREATER_EQUAL 0)
string(SUBSTRING "${directory}" ${is_prefixed_in_subdir} -1
directory_path
)
list(APPEND new_exported_include_directories
$<BUILD_INTERFACE:${directory_path}>
)
else()
list(APPEND new_exported_include_directories ${directory})
endif()
endforeach()
set(exported_include_directories ${new_exported_include_directories})
string(REPLACE "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/include" ""
exported_include_directories
"${exported_include_directories}"

View File

@ -0,0 +1,198 @@
# Copyright (c) 2017-2023 Universidade de Brasília
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License version 2 as published by the Free
# Software Foundation;
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
# Place, Suite 330, Boston, MA 02111-1307 USA
#
# Author: Gabriel Ferreira <gabrielcarvfer@gmail.com>
# Set default installation directory
set(VCPKG_DIR "${PROJECT_SOURCE_DIR}/vcpkg")
# Check if there is an existing vcpkg installation in the user directory
if(WIN32)
set(user_dir $ENV{USERPROFILE})
else()
set(user_dir $ENV{HOME})
endif()
# Override the default vcpkg installation directory in case it does
if(EXISTS "${user_dir}/vcpkg")
set(VCPKG_DIR "${user_dir}/vcpkg")
endif()
find_package(Git)
if(${CMAKE_SIZEOF_VOID_P} EQUAL 8)
set(VCPKG_TARGET_ARCH x64)
else()
set(VCPKG_TARGET_ARCH x86)
endif()
if(WIN32)
set(VCPKG_EXEC vcpkg.exe)
set(VCPKG_TRIPLET ${VCPKG_TARGET_ARCH}-windows)
else()
set(VCPKG_EXEC vcpkg)
if(NOT APPLE) # LINUX
set(VCPKG_TRIPLET ${VCPKG_TARGET_ARCH}-linux)
else()
set(VCPKG_TRIPLET ${VCPKG_TARGET_ARCH}-osx)
endif()
endif()
# https://learn.microsoft.com/en-us/vcpkg/users/buildsystems/cmake-integration
set(VCPKG_TARGET_TRIPLET ${VCPKG_TRIPLET})
set(VCPKG_MANIFEST ${PROJECT_SOURCE_DIR}/vcpkg.json)
function(setup_vcpkg)
message(STATUS "vcpkg: setting up support in ${VCPKG_DIR}")
# Check if vcpkg was downloaded previously
if(EXISTS "${VCPKG_DIR}")
# Vcpkg already downloaded
message(STATUS "vcpkg: folder already exists, skipping git download")
else()
if(NOT ${Git_FOUND})
message(FATAL_ERROR "vcpkg: Git is required, but it was not found")
endif()
get_filename_component(VCPKG_PARENT_DIR ${VCPKG_DIR} DIRECTORY)
execute_process(
COMMAND ${GIT_EXECUTABLE} clone --depth 1
https://github.com/microsoft/vcpkg.git
WORKING_DIRECTORY "${VCPKG_PARENT_DIR}/"
)
endif()
if(${MSVC})
message(FATAL_ERROR "vcpkg: Visual Studio is unsupported")
else()
# Check if required packages are installed (unzip curl tar)
if(WIN32)
find_program(ZIP_PRESENT zip.exe)
find_program(UNZIP_PRESENT unzip.exe)
find_program(CURL_PRESENT curl.exe)
find_program(TAR_PRESENT tar.exe)
else()
find_program(ZIP_PRESENT zip)
find_program(UNZIP_PRESENT unzip)
find_program(CURL_PRESENT curl)
find_program(TAR_PRESENT tar)
endif()
if(${ZIP_PRESENT} STREQUAL ZIP_PRESENT-NOTFOUND)
message(FATAL_ERROR "vcpkg: Zip is required, but is not installed")
endif()
if(${UNZIP_PRESENT} STREQUAL UNZIP_PRESENT-NOTFOUND)
message(FATAL_ERROR "vcpkg: Unzip is required, but is not installed")
endif()
if(${CURL_PRESENT} STREQUAL CURL_PRESENT-NOTFOUND)
message(FATAL_ERROR "vcpkg: Curl is required, but is not installed")
endif()
if(${TAR_PRESENT} STREQUAL TAR_PRESENT-NOTFOUND)
message(FATAL_ERROR "vcpkg: Tar is required, but is not installed")
endif()
endif()
# message(WARNING "Checking VCPKG bootstrapping") Check if vcpkg was
# bootstrapped previously
if(EXISTS "${VCPKG_DIR}/${VCPKG_EXEC}")
message(STATUS "vcpkg: already bootstrapped")
else()
# message(WARNING "vcpkg: bootstrapping")
set(COMPILER_ENFORCING)
if(WIN32)
set(command bootstrap-vcpkg.bat -disableMetrics)
else()
# if(NOT APPLE) #linux/bsd
set(command bootstrap-vcpkg.sh -disableMetrics)
# else() set(command bootstrap-vcpkg.sh)# --allowAppleClang) endif()
endif()
execute_process(
COMMAND ${COMPILER_ENFORCING} ${VCPKG_DIR}/${command}
WORKING_DIRECTORY ${VCPKG_DIR}
)
# message(STATUS "vcpkg: bootstrapped") include_directories(${VCPKG_DIR})
set(ENV{VCPKG_ROOT} ${VCPKG_DIR})
endif()
if(NOT WIN32)
execute_process(COMMAND chmod +x ${VCPKG_DIR}/${VCPKG_EXEC})
endif()
set(CMAKE_PREFIX_PATH
"${VCPKG_DIR}/installed/${VCPKG_TRIPLET}/;${CMAKE_PREFIX_PATH}"
PARENT_SCOPE
)
# Install packages in manifest mode
if(EXISTS ${VCPKG_MANIFEST})
message(STATUS "vcpkg: detected a vcpkg manifest file: ${VCPKG_MANIFEST}")
execute_process(
COMMAND ${VCPKG_DIR}/${VCPKG_EXEC} install --triplet ${VCPKG_TRIPLET}
--x-install-root=${VCPKG_DIR}/installed RESULT_VARIABLE res
)
if(${res} EQUAL 0)
message(STATUS "vcpkg: packages defined in the manifest were installed")
else()
message(
FATAL_ERROR
"vcpkg: packages defined in the manifest failed to be installed"
)
endif()
endif()
endfunction()
function(add_package package_name)
# Early exit in case vcpkg support is not enabled
if(NOT ${NS3_VCPKG})
message(${HIGHLIGHTED_STATUS}
"vcpkg: support is disabled. Not installing: ${package_name}"
)
return()
endif()
# Early exit in case a vcpkg.json manifest file is present
if(EXISTS ${VCPKG_MANIFEST})
file(READ ${VCPKG_MANIFEST} contents)
if(${contents} MATCHES ${package_name})
message(STATUS "vcpkg: ${package_name} was installed")
return()
else()
message(
FATAL_ERROR
"vcpkg: manifest mode in use, but ${package_name} is not listed in ${VCPKG_MANIFEST}"
)
endif()
endif()
# Normal exit
message(STATUS "vcpkg: ${package_name} will be installed")
execute_process(
COMMAND ${VCPKG_DIR}/${VCPKG_EXEC} install ${package_name} --triplet
${VCPKG_TRIPLET} RESULT_VARIABLE res
)
if(${res} EQUAL 0)
message(STATUS "vcpkg: ${package_name} was installed")
else()
message(FATAL_ERROR "vcpkg: ${package_name} failed to be installed")
endif()
endfunction()
if(${NS3_VCPKG})
setup_vcpkg()
endif()

View File

@ -150,6 +150,7 @@ set(CMAKE_HEADER_OUTPUT_DIRECTORY ${CMAKE_OUTPUT_DIRECTORY}/include/ns3)
set(THIRD_PARTY_DIRECTORY ${PROJECT_SOURCE_DIR}/3rd-party)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
link_directories(${CMAKE_OUTPUT_DIRECTORY}/lib)
file(MAKE_DIRECTORY ${CMAKE_OUTPUT_DIRECTORY})
# Get installation folder default values for each platform and include package
# configuration macro
@ -751,6 +752,51 @@ macro(process_options)
)
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/build-support/3rd-party")
# Include our package managers
# cmake-format: off
# Starting with a custom cmake file that provides a Hunter-like interface to vcpkg
# Use add_package(package) to install a package
# Then find_package(package) to use it
# cmake-format: on
include(ns3-vcpkg-hunter)
# Then the beautiful CPM manager (too bad it doesn't work with everything)
# https://github.com/cpm-cmake/CPM.cmake
if(${NS3_CPM})
set(CPM_DOWNLOAD_VERSION 0.38.2)
set(CPM_DOWNLOAD_LOCATION
"${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake"
)
if(NOT (EXISTS ${CPM_DOWNLOAD_LOCATION}))
message(STATUS "Downloading CPM.cmake to ${CPM_DOWNLOAD_LOCATION}")
file(
DOWNLOAD
https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake
${CPM_DOWNLOAD_LOCATION}
)
endif()
include(${CPM_DOWNLOAD_LOCATION})
set(CPM_USE_LOCAL_PACKAGES ON)
endif()
# Package manager test block
if(TEST_PACKAGE_MANAGER)
if(${TEST_PACKAGE_MANAGER} STREQUAL "CPM")
cpmaddpackage(
NAME ARMADILLO GIT_TAG 6cada351248c9a967b137b9fcb3d160dad7c709b
GIT_REPOSITORY https://gitlab.com/conradsnicta/armadillo-code.git
)
find_package(ARMADILLO REQUIRED)
message(STATUS "Armadillo was found? ${ARMADILLO_FOUND}")
elseif(${TEST_PACKAGE_MANAGER} STREQUAL "VCPKG")
add_package(Armadillo)
find_package(Armadillo REQUIRED)
message(STATUS "Armadillo was found? ${ARMADILLO_FOUND}")
else()
find_package(Armadillo REQUIRED)
endif()
endif()
# End of package managers
set(ENABLE_EIGEN False)
if(${NS3_EIGEN})
find_package(Eigen3 QUIET)

View File

@ -0,0 +1,42 @@
if(NOT
TEST_PACKAGE_MANAGER
)
message(
STATUS "Skipping test module because TEST_PACKAGE_MANAGER is not set."
)
return()
endif()
set(armadillo)
if(${TEST_PACKAGE_MANAGER}
STREQUAL
"CPM"
)
set(armadillo
armadillo
)
include_directories(${CMAKE_BINARY_DIR}/_deps/armadillo-src/include)
elseif(
${TEST_PACKAGE_MANAGER}
STREQUAL
"VCPKG"
)
set(armadillo
${ARMADILLO_LIBRARIES}
)
include_directories(${ARMADILLO_INCLUDE_DIRS})
else()
message(FATAL_ERROR "zoincs")
message(
STATUS
"Skipping test module because TEST_PACKAGE_MANAGER is set to an unsupported value."
)
return()
endif()
build_lib(
LIBNAME test-package-managers
SOURCE_FILES src.cc
LIBRARIES_TO_LINK ${libcore}
${armadillo}
)

View File

@ -0,0 +1,10 @@
#include <armadillo>
int
main(int argc, char** argv)
{
arma::arma_rng::set_seed_random();
arma::Mat<double> mat = arma::randu(4, 4);
std::cout << "mat:\n" << mat << "\n";
return 0;
}

5
ns3
View File

@ -505,6 +505,10 @@ def clean_pip_packaging_artifacts(dry_run=False):
remove_dir(directory, dry_run)
def clean_vcpkg_artifacts(dry_run=False):
remove_dir(os.path.join(ns3_path, "vcpkg"), dry_run)
def search_cmake_cache(build_profile):
# Search for the CMake cache
cmake_cache_files = glob.glob("%s/**/CMakeCache.txt" % ns3_path, recursive=True)
@ -1445,6 +1449,7 @@ def main():
clean_cmake_artifacts(dry_run=args.dry_run)
clean_docs_and_tests_artifacts(dry_run=args.dry_run)
clean_pip_packaging_artifacts(dry_run=args.dry_run)
clean_vcpkg_artifacts(dry_run=args.dry_run)
# We end things earlier when cleaning
return

View File

@ -1,6 +1,6 @@
#! /usr/bin/env python3
#
# Copyright (c) 2021 Universidade de Brasília
# Copyright (c) 2021-2023 Universidade de Brasília
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
@ -2834,6 +2834,98 @@ class NS3ExpectedUseTestCase(NS3BaseTestCase):
self.assertIn("scratch-simulator", stdout)
self.assertIn("(lldb) target create", stdout)
def test_18_CpmAndVcpkgManagers(self):
"""!
Test if CPM and Vcpkg package managers are working properly
@return None
"""
# Clean the ns-3 configuration
return_code, stdout, stderr = run_ns3("clean")
self.assertEqual(return_code, 0)
# Cleanup VcPkg leftovers
if os.path.exists("vcpkg"):
shutil.rmtree("vcpkg")
# Copy a test module that consumes armadillo
destination_src = os.path.join(ns3_path, "src/test-package-managers")
# Remove pre-existing directories
if os.path.exists(destination_src):
shutil.rmtree(destination_src)
# Always use a fresh copy
shutil.copytree(os.path.join(ns3_path, "build-support/test-files/test-package-managers"),
destination_src)
with DockerContainerManager(self, "ubuntu:22.04") as container:
# Install toolchain
container.execute("apt-get update")
container.execute("apt-get install -y python3 cmake g++ ninja-build")
# Verify that Armadillo is not available and that we did not
# add any new unnecessary dependency when features are not used
try:
container.execute(
"./ns3 configure -- -DTEST_PACKAGE_MANAGER:STRING=ON")
self.skipTest("Armadillo is already installed")
except DockerException as e:
pass
# Clean cache to prevent dumb errors
return_code, stdout, stderr = run_ns3("clean")
self.assertEqual(return_code, 0)
# Install CPM and VcPkg shared dependency
container.execute("apt-get install -y git")
# Install Armadillo with CPM
try:
container.execute(
"./ns3 configure -- -DNS3_CPM=ON -DTEST_PACKAGE_MANAGER:STRING=CPM")
except DockerException as e:
self.fail()
# Try to build module using CPM's Armadillo
try:
container.execute(
"./ns3 build test-package-managers")
except DockerException as e:
self.fail()
# Clean cache to prevent dumb errors
return_code, stdout, stderr = run_ns3("clean")
self.assertEqual(return_code, 0)
# Install VcPkg dependencies
container.execute("apt-get install -y zip unzip tar curl")
# Install Armadillo dependencies
container.execute("apt-get install -y pkg-config gfortran")
# Install VcPkg
try:
container.execute(
"./ns3 configure -- -DNS3_VCPKG=ON")
except DockerException as e:
self.fail()
# Install Armadillo with VcPkg
try:
container.execute("./ns3 configure -- -DTEST_PACKAGE_MANAGER:STRING=VCPKG")
except DockerException as e:
self.fail()
# Try to build module using VcPkg's Armadillo
try:
container.execute(
"./ns3 build test-package-managers")
except DockerException as e:
self.fail()
# Remove test module
if os.path.exists(destination_src):
shutil.rmtree(destination_src)
class NS3QualityControlTestCase(unittest.TestCase):
"""!