From 5fe2f5454cd07362f9f348a59999787704e2477e Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Tue, 16 Apr 2024 09:27:59 +0200 Subject: [PATCH] Improve the conan to build flow. --- BUILDING.md | 116 +++++++++++++++++++++++++++++++++++++++++++++---- CMakeLists.txt | 2 +- conanfile.py | 53 ++++++++++++++++++++-- 3 files changed, 157 insertions(+), 14 deletions(-) diff --git a/BUILDING.md b/BUILDING.md index 15b0ca86bf8..c8e76289069 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -1,20 +1,101 @@ # Building with conan v2 -Check you have conan v2, and add the nrel-v2 remote to grab ruby and swig/4.1.1 +Check you have `conan >= 2`, and add the `nrel-v2` remote to grab `ruby` and `swig/4.1.1`. ```shell conan --version conan remote add -f nrel-v2 http://conan.openstudio.net/artifactory/api/conan/conan-v2 ``` +## Install the conan dependencies into a build folder ```shell -conan install . --output-folder=../OS-build-release-v2 --build=missing -c tools.cmake.cmaketoolchain:generator=Ninja -s compiler.cppstd=20 -s build_type=Release -cd ../OS-build-release-v2 +conan install . --output-folder=../OS-build-release --build=missing -c tools.cmake.cmaketoolchain:generator=Ninja -s compiler.cppstd=20 -s build_type=Release +``` + +You can also do another configuration, such as `Debug`, `RelWithDeb`, etc + +```shell +conan install . --output-folder=../OS-build --build=missing -c tools.cmake.cmaketoolchain:generator=Ninja -s compiler.cppstd=20 -s build_type=Debug +``` + +You'll have the `conan-release` and `conan-debug` CMake Presets in the root folder. Do `cmake --list-presets` to list the available presets (which are in `CMakeUserPresets.json`) + +*Side note:* If you want a specific configure option (such as a build folder in Release mode where you build with `-DBUILD_CSHARP_BINDINGS:BOOL=ON`) in a different build dir for the same source dir, you probably will need to go and edit the `/CMakePresets.json` to rename it to another configuration name so it does not clash with the preset `conan-release` + +## CMake Configure and build + +### With presets + +#### Why are Presets recommended + +The recommend flow is to use [CMake Presets](https://cmake.org/cmake/help/latest/manual/cmake-presets.7.html). + +If you notice the messages printed to the console when you run the `conan install` command from above, +you'll see that the `conanfile` actually defines common build variables for you already, +such as defining which `CPack` Generators to use depending on your target platform, trying to infer the `Python_ROOT_DIR` etc + +
conanfile.py: Calling generate()
+conanfile.py: Generators folder: /path/to/OS-build-release
+conanfile.py: Setting PYTHON_VERSION and Python_ROOT_DIR from your current python: 3.8.13, '/home/julien/.pyenv/versions/3.8.13'
+conanfile.py: CMakeToolchain generated: conan_toolchain.cmake
+conanfile.py: Preset 'conan-release' added to CMakePresets.json. Invoke it manually using 'cmake --preset conan-release' if using CMake>=3.23
+conanfile.py: If your CMake version is not compatible with CMakePresets (<3.23) call cmake like:
+    cmake <path> -G Ninja -DCMAKE_TOOLCHAIN_FILE=/path/to/OS-build-release/conan_toolchain.cmake \
+      -DBUILD_CLI=ON -DBUILD_RUBY_BINDINGS=ON -DBUILD_PYTHON_BINDINGS=ON \
+      -DBUILD_PYTHON_PIP_PACKAGE=OFF -DBUILD_TESTING=ON -DBUILD_BENCHMARK=ON \
+      -DCPACK_BINARY_TGZ=ON -DCPACK_BINARY_IFW=OFF -DCPACK_BINARY_DEB=ON -DCPACK_BINARY_NSIS=OFF \
+      -DCPACK_BINARY_RPM=OFF -DCPACK_BINARY_STGZ=OFF -DCPACK_BINARY_TBZ2=OFF \
+      -DCPACK_BINARY_TXZ=OFF -DCPACK_BINARY_TZ=OFF \
+      -DPYTHON_VERSION=3.8.13 -DPython_ROOT_DIR=/home/julien/.pyenv/versions/3.8.13 \
+      -DCMAKE_POLICY_DEFAULT_CMP0091=NEW -DCMAKE_BUILD_TYPE=Release
+conanfile.py: CMakeToolchain generated: CMakePresets.json
+conanfile.py: CMakeToolchain generated: ../OpenStudio/CMakeUserPresets.json
+conanfile.py: Generating aggregated env files
+conanfile.py: Generated aggregated env files: ['conanbuild.sh', 'conanrun.sh']
+Install finished successfully
+
+ +**Note that this is also supported by Visual Studio (MSVC)**. + +#### Configure and build with Presets + +Run these commands from the **source** directory (`OpenStudio/`). + +```shell +cmake --preset conan-release [any_futher_configuration_options] +``` + +Example: + +``` +cmake --preset conan-release \ + -DBUILD_PYTHON_BINDINGS:BOOL=ON -DBUILD_PYTHON_PIP_PACKAGE:BOOL=ON \ + -DPYTHON_VERSION=3.8.13 -DPython_ROOT_DIR:PATH=$HOME/.pyenv/versions/3.8.13/ \ + -DBUILD_CSHARP_BINDINGS:BOOL=ON +``` + +Building + +``` +cmake --build --preset conan-release +``` + +### Atlernatively: manual CMake + +First, go to the **build** directory, and **activate the conan build environment**. + +```shell +cd ../OS-build-release +# Unix . ./conanbuild.sh +# Windows +call conanbuild.bat +``` + +Still in the build directory, run cmake, but do pass the `CMAKE_TOOLCHAIN_FILE` -# Run cmake, but do pass the CMAKE_TOOLCHAIN_FILE -#/OS-build-release-v2 % +``` cmake -G Ninja -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_BUILD_TYPE:STRING=Release \ -DBUILD_TESTING:BOOL=ON -DCPACK_BINARY_TGZ:BOOL=ON -DCPACK_BINARY_DEB:BOOL=ON \ -DCPACK_BINARY_IFW:BOOL=OFF -DCPACK_BINARY_NSIS:BOOL=OFF -DCPACK_BINARY_RPM:BOOL=OFF -DCPACK_BINARY_STGZ:BOOL=OFF \ @@ -23,17 +104,34 @@ cmake -G Ninja -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_BUILD_TYPE:S -DPYTHON_VERSION=3.8.13 -DPython_ROOT_DIR:PATH=/home/julien/.pyenv/versions/3.8.13/ \ -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=ON \ ../OpenStudio +``` -# You can deactivate now if you want +You can deactivate now if you want + +``` +# Unix . ./deactivate_conanbuild.sh +# Windows +call deactivate_conanbuild.bat ``` -Note that is also makes cmake presets, at root of OpenStudio, you can also try `cmake --list-presets`. To configure `cmake --preset conan-release`; to build `cmake --build --preset conan-release`. +# Full Example + +``` +git clone git@github.com/NREL/OpenStudio.git +cd OpenStudio +conan install . --output-folder=../OS-build-release --build=missing -c tools.cmake.cmaketoolchain:generator=Ninja -s compiler.cppstd=20 -s build_type=Release +cmake --preset conan-release +cmake --build --preset conan-release +``` +# Updating the Conan Lockfile -If you want to update a dependency in the conan.lock, just delete the line, and use this: +If you want to update a dependency in the `conan.lock`, just delete the line, and use this: ```shell -conan install . --output-folder=../OS-build-release-v2 --build=missing -c tools.cmake.cmaketoolchain:generator=Ninja -s compiler.cppstd=20 -s build_type=Release --lockfile-partial --lockfile-out=conan.lock +conan install . --output-folder=../OS-build-release --build=missing \ + -c tools.cmake.cmaketoolchain:generator=Ninja -s compiler.cppstd=20 -s build_type=Release \ + --lockfile-partial --lockfile-out=conan.lock ``` diff --git a/CMakeLists.txt b/CMakeLists.txt index 7336abc1043..7e7cf6859a9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ message(STATUS "Using CMake ${CMAKE_VERSION}") -cmake_minimum_required(VERSION 3.20.0) +cmake_minimum_required(VERSION 3.23.0) cmake_policy(SET CMP0048 NEW) set(CMAKE_CXX_STANDARD 20) diff --git a/conanfile.py b/conanfile.py index 19d3d0cad1d..4e691baba18 100644 --- a/conanfile.py +++ b/conanfile.py @@ -1,9 +1,14 @@ +import sys +from pathlib import Path from conan import ConanFile from conan.tools.apple import is_apple_os +from conan.tools.cmake import CMakeToolchain -class CompressorRecipe(ConanFile): +required_conan_version = ">=2.0" + +class OpenStudioBuildRecipe(ConanFile): settings = "os", "compiler", "build_type", "arch" - generators = "CMakeToolchain", "CMakeDeps" + generators = "CMakeDeps" # CMakeToolchain explicitly instantiated options = { "with_testing": [True, False], @@ -45,5 +50,45 @@ def requirements(self): self.requires("benchmark/1.8.3") - #def build_requirements(self): - # self.tool_requires("cmake/3.22.6") + # def build_requirements(self): + # self.tool_requires("cmake/3.22.6") + + def generate(self): + tc = CMakeToolchain(self) + + tc.cache_variables["BUILD_CLI"] = True + tc.cache_variables["BUILD_RUBY_BINDINGS"] = True + tc.cache_variables["BUILD_PYTHON_BINDINGS"] = True + tc.cache_variables["BUILD_PYTHON_PIP_PACKAGE"] = False + + tc.cache_variables["BUILD_TESTING"] = bool(self.options.with_testing) + tc.cache_variables["BUILD_BENCHMARK"] = bool(self.options.with_benchmark) + + tc.cache_variables["CPACK_BINARY_TGZ"] = True + tc.cache_variables["CPACK_BINARY_IFW"] = False + tc.cache_variables["CPACK_BINARY_DEB"] = False + if self.settings.build_type == "Release": + if is_apple_os(self) or self.settings.os == "Windows": + tc.cache_variables["CPACK_BINARY_IFW"] = True + else: + tc.cache_variables["CPACK_BINARY_DEB"] = True + tc.cache_variables["CPACK_BINARY_NSIS"] = False + tc.cache_variables["CPACK_BINARY_RPM"] = False + tc.cache_variables["CPACK_BINARY_STGZ"] = False + tc.cache_variables["CPACK_BINARY_TBZ2"] = False + tc.cache_variables["CPACK_BINARY_TXZ"] = False + tc.cache_variables["CPACK_BINARY_TZ"] = False + + v = sys.version_info + if (v.major, v.minor) == (3, 8): + python_version = f"{v.major}.{v.minor}.{v.micro}" + self.output.info(f"Setting PYTHON_VERSION and Python_ROOT_DIR from your current python: {python_version}, '{sys.base_prefix}'") + tc.cache_variables["PYTHON_VERSION"] = python_version + tc.cache_variables["Python_ROOT_DIR"] = Path(sys.base_prefix) + else: + self.output.warning( + "Your current python is not in the 3.8.x range, which is what we target.\n" + "You'll need to pass it properly when configuring CMake\n" + "via -DPYTHON_VERSION:STRING='3.8.xx' and -DPython_ROOT_DIR:PATH='/path/to/python3.8/'" + ) + tc.generate()