Open schifazl opened 6 months ago
Hi @schifazl - thank you for asking this question.
To summarize: can I use a Conan dependency without the Conan toolchain file? If not, is there a way to put "somewhere" my actual toolchain file so that it can be used with Conan?
You can actually do both, although I would recommend the method where the Conan-generated conan_toolchain.cmake
, chain-loads your custom toolchain.
You can use the tools.cmake.cmaketoolchain:user_toolchain
conf to specify a custom, use-provided toolchain - then conan_toolchain.cmake
will include this directly. You can specify this either:
-c tools.cmake.cmaketoolchain:user_toolchain=/path/to/gcc-toolchain.cmake
[conf]
section of your host profilepackage_info()
method, which will affect consumers when building other librariesLet me know if this helps or if you need any more details.
Depending on the complexity of your custom gcc-toolchain.cmake
, you may be able to specify the same information in the Conan profile directly, with the added advatange that Conan is able to propagate that information when building things in other build systems as well (e.g. autotools, meson) - whereas a custom gcc-toolchain.cmake only works with CMake. Although wether you would benefit from this depends on your needs :)
Thanks and sorry for the late reply, but I had other stories to close and just now returned on this issue 😅
I'm trying to use the [conf] method (eventually I think that I'll move the toolchain to a separate Conan recipe as per your third suggestion, but one thing at a time), but I'm having difficulties:
tools.cmake.cmaketoolchain:user_toolchain=["gcc-toolchain.cmake"]
conan install . --output-folder=build --build=missing --profile=./conan.conf ; cmake --preset=release
include("gcc-toolchain.cmake")
lineI tried to change the conf line in various ways, like ../gcc-toolchain.cmake
or prepending it with various CMake (and Conan) standard variables, like CMAKE_SOURCE_DIR
, or the jinja2 method with absolutely no luck. The only way to make it work is by providing the absolute path to the gcc-toolchain.cmake file.
Is this intended behavior or it's just me that I'm a total noob both in Conan and in CMake? 😅
Hi @schifazl
Indeed In the conf file I put tools.cmake.cmaketoolchain:user_toolchain=["gcc-toolchain.cmake"]
with a relative path will not work. It is necessary to provide the full path.
In profile jinja
syntax, specially when the conf
is provided in a profile, with the profile_dir
variable, see https://docs.conan.io/2/examples/tools/cmake/cmake_toolchain/inject_cmake_variables.html
[conf]
tools.cmake.cmaketoolchain:user_toolchain+={{profile_dir}}/myvars.cmake
In general, adding things to profile files and managing the profiles with conan config install
would be recommended, easier to maintain, reproduce and share than relying on passing many command line arguments.
Thanks, it worked! 😄
In general, adding things to profile files and managing the profiles with
conan config install
would be recommended, easier to maintain, reproduce and share than relying on passing many command line arguments.
I'm not sure here what are you suggesting... replacing my toolchain file with variables in the conan.conf files, or replacing the --output-folder=build --build=missing
parameters?
I'm not sure here what are you suggesting... replacing my toolchain file with variables in the conan.conf files, or replacing the --output-folder=build --build=missing parameters?
I am suggesting not passing conf
in the command line like -c tools.cmake.cmaketoolchain:user_toolchain=...
and probably not adding that to the global.conf
file either.
That kind of configuration can be added to the [conf]
section of a profile file. Note that the name conan.conf
for a profile, like you suggested above in --profile=./conan.conf
is not recommended, as the .conf
extension is other concept. I'd recommend using profiles with .txt
or .profile
or even without extension.
The the --output-folder=build
can be ommitted if using layout()
(or [layout]
in conanfile.txt), making the user command simpler and shorter to type.
Great thanks, I applied your suggestions!
I had some trouble compiling my project using a header-only Conan package (made by me).
Using the recommended method for Conan 2, the compilation doesn't work (the header dir is not added to the compiler command with the -I
switch:
find_package("cmsis5")
target_link_libraries(${PROJECT_NAME} PUBLIC cmsis5::cmsis5)
It now works by adding these lines in the CMakeLists.txt
file:
find_package("cmsis5")
include_directories(${cmsis5_INCLUDE_DIRS})
target_link_libraries(${PROJECT_NAME} ${cmsis5_LIBRARIES})
But... This is from Conan 1.64 guide. Is it still OK?
Edit: It's enough to use
find_package("cmsis5")
include_directories(${cmsis5_INCLUDE_DIRS})
Hi @schifazl
include_directories(${cmsis5_INCLUDE_DIRS})
No, this shouldn't be necessary, and even if it is a header-only library, the recommended way is target_link_libraries(${PROJECT_NAME} PUBLIC cmsis5::cmsis5)
, and it should be enough.
I'd say it is possible that you are missing some detail in your recipe, like in Conan 2 package_type = "header-library"
is strongly recommended, or maybe there is something else missing in the recipe. If you want to share it, we could have a look.
Sure, this is the library recipe:
from conan import ConanFile
from conan.tools.files import copy
class cmsis5Recipe(ConanFile):
name = "cmsis5"
version = "0.1.0"
package_type = "header-library"
# Optional metadata
license = "<Put the package license here>"
author = "<Put your name here> <And your email here>"
url = "<Package recipe repository url here, for issues about the package>"
description = "<Description of cmsis-5 package here>"
topics = ("<Put some tag here>", "<here>", "<and here>")
# No settings/options are necessary, this is header only
exports_sources = "include/*"
# We can avoid copying the sources to the build folder in the cache
no_copy_source = True
def package(self):
# This will also copy the "include" folder
copy(self, "*.h", self.source_folder, self.package_folder)
def package_info(self):
# For header-only packages, libdirs and bindirs are not used
# so it's necessary to set those as empty.
self.cpp_info.bindirs = []
self.cpp_info.libdirs = []
# Generate both MyFileNameConfig.cmake and FindMyFileName.cmake
self.cpp_info.set_property("cmake_find_mode", "both")
And this is the recipe of the main project:
from conan import ConanFile
class S300Recipe(ConanFile):
# Binary configuration
settings = "compiler", "build_type", "arch"
generators = "CMakeDeps", "CMakeToolchain"
def requirements(self):
self.requires("cmsis5/0.1.0")
def layout(self):
self.folders.build = "build"
self.folders.generators = "build"
Uhm, I am not sure what is happening.
Maybe it is worth adding in the consumer the package_type = "application"
or library/shared-library/static-library
, but I am not sure that would be the main issue. Maybe the settings = "os"
that is missing could also be.
I have tried to put it as a full example, that can be tested with conan create .
and it seems to work: example.zip Maybe if you can put a fully reproducible example including the CMakeLists.txt and simple source files, that could clarify it.
I prepared a test with just the main .c file and the dependency (conanfile buried in ra\arm\CMSIS_5\CMSIS\Core ). It doesn't link, but I think this is not important for the purpose of this issue.
I create the dependency with conan create .\ra\arm\CMSIS_5\CMSIS\Core --profile:all .\conan.profile
and the main project with remove-item build -recurse ; conan install . --profile:all=./conan.profile ; cmake --preset=release ; cmake --build --preset=release
You'll have to change the TOOLCHAIN_PREFIX
variable in the CMakePresets file, I presume.
I am trying to reproduce, but I don't have this compiler installed "TOOLCHAIN_PREFIX": "C:/Program Files (x86)/Arm GNU Toolchain arm-none-eabi/12.2 mpacbti-rel1"
, so this would be difficult. Isn't it possible to reproduce it without such specific compiler? It might be possible to reproduce it with the standard msvc compiler?
Adding full logs to the repo that prints the full output and error might help.
A quick possible hint is that when using a specific generator as Ninja Multi-Config
it is necessary to tell Conan, with -c tools.cmake.cmaketoolchain:generator="Ninja Multi-Config"
, so things are aligned.
I am trying to reproduce, but I don't have this compiler installed
"TOOLCHAIN_PREFIX": "C:/Program Files (x86)/Arm GNU Toolchain arm-none-eabi/12.2 mpacbti-rel1"
, so this would be difficult. Isn't it possible to reproduce it without such specific compiler? It might be possible to reproduce it with the standard msvc compiler?
I don't know 😅 I have to try, never used msvc for embedded work...
Adding full logs to the repo that prints the full output and error might help.
Successful compilation (when using target_include_directories):
PS C:\work\src\myproject> remove-item build -recurse ; conan install . --profile:all=./conan.profile ; cmake --preset=release ; cmake --build --preset=release
======== Input profiles ========
Profile host:
[settings]
arch=armv8.3
compiler=gcc
compiler.libcxx=libstdc++
compiler.version=13.2
os=baremetal
[conf]
tools.cmake.cmaketoolchain:user_toolchain=['C:\\work\\src\\myproject/gcc-toolchain.cmake']
Profile build:
[settings]
arch=armv8.3
compiler=gcc
compiler.libcxx=libstdc++
compiler.version=13.2
os=baremetal
[conf]
tools.cmake.cmaketoolchain:user_toolchain=['C:\\work\\src\\myproject/gcc-toolchain.cmake']
======== Computing dependency graph ========
Graph root
conanfile.py: C:\work\src\myproject\conanfile.py
Requirements
cmsis5/0.1.0#c5711ac2ca3283714557f93b4bd51fa7 - Cache
======== Computing necessary packages ========
Requirements
cmsis5/0.1.0#c5711ac2ca3283714557f93b4bd51fa7:da39a3ee5e6b4b0d3255bfef95601890afd80709#c3c71f623eb728469d6afcc66453dfaa - Cache
======== Installing packages ========
cmsis5/0.1.0: Already installed! (1 of 1)
======== Finalizing install (deploy, generators) ========
conanfile.py: Writing generators to C:\work\src\myproject\build
conanfile.py: Generator 'CMakeDeps' calling 'generate()'
conanfile.py: CMakeDeps necessary find_package() and targets for your CMakeLists.txt
find_package(cmsis5)
target_link_libraries(... cmsis5::cmsis5)
conanfile.py: Generator 'CMakeToolchain' calling 'generate()'
conanfile.py: CMakeToolchain generated: conan_toolchain.cmake
conanfile.py: Preset 'conan-default' added to CMakePresets.json. Invoke it manually using 'cmake --preset conan-default' if using CMake>=3.23
conanfile.py: If your CMake version is not compatible with CMakePresets (<3.23) call cmake like: 'cmake <path> -G "Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE=C:\work\src\myproject\build\conan_toolchain.cmake -DCMAKE_POLICY_DEFAULT_CMP0091=NEW'
conanfile.py: CMakeToolchain generated: CMakePresets.json
conanfile.py: CMakeToolchain generated: ..\CMakeUserPresets.json
conanfile.py: Generating aggregated env files
conanfile.py: Generated aggregated env files: ['conanbuild.sh', 'conanrun.sh']
Install finished successfully
Preset CMake variables:
CMAKE_BUILD_TYPE="Release"
CMAKE_TOOLCHAIN_FILE:FILEPATH="conan_toolchain.cmake"
TOOLCHAIN_PREFIX="C:/Program Files (x86)/Arm GNU Toolchain arm-none-eabi/12.2 mpacbti-rel1"
-- Using Conan toolchain: C:/work/src/devops/s300-ufo/build/conan_toolchain.cmake
-- The C compiler identification is GNU 12.2.1
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: C:/Program Files (x86)/Arm GNU Toolchain arm-none-eabi/12.2 mpacbti-rel1/bin/arm-none-eabi-gcc.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Conan: Target declared 'cmsis5::cmsis5'
-- Found cmsis5: 0.1.0 (found version "0.1.0")
-- Configuring done (5.3s)
-- Generating done (0.2s)
-- Build files have been written to: C:/work/src/devops/s300-ufo/build
[18/43] Building C object CMakeFiles/myproject.dir/Debug/src/view-state-manager.c.obj
C:/work/src/devops/s300-ufo/src/view-state-manager.c: In function 'ViewStateUpdate':
C:/work/src/devops/s300-ufo/src/view-state-manager.c:182:25: warning: assignment discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
182 | actions = ViewGetActionTable(globalViewState.nextView);
| ^
[43/43] Linking C executable Debug\myproject.out
Unsuccessful compilation (when using target_link_libraries):
======== Input profiles ========
Profile host:
[settings]
arch=armv8.3
compiler=gcc
compiler.libcxx=libstdc++
compiler.version=13.2
os=baremetal
[conf]
tools.cmake.cmaketoolchain:user_toolchain=['C:\\work\\src\\myproject/gcc-toolchain.cmake']
Profile build:
[settings]
arch=armv8.3
compiler=gcc
compiler.libcxx=libstdc++
compiler.version=13.2
os=baremetal
[conf]
tools.cmake.cmaketoolchain:user_toolchain=['C:\\work\\src\\myproject/gcc-toolchain.cmake']
======== Computing dependency graph ========
Graph root
conanfile.py: C:\work\src\myproject\conanfile.py
Requirements
cmsis5/0.1.0#c5711ac2ca3283714557f93b4bd51fa7 - Cache
======== Computing necessary packages ========
Requirements
cmsis5/0.1.0#c5711ac2ca3283714557f93b4bd51fa7:da39a3ee5e6b4b0d3255bfef95601890afd80709#c3c71f623eb728469d6afcc66453dfaa - Cache
======== Installing packages ========
cmsis5/0.1.0: Already installed! (1 of 1)
======== Finalizing install (deploy, generators) ========
conanfile.py: Writing generators to C:\work\src\myproject\build
conanfile.py: Generator 'CMakeDeps' calling 'generate()'
conanfile.py: CMakeDeps necessary find_package() and targets for your CMakeLists.txt
find_package(cmsis5)
target_link_libraries(... cmsis5::cmsis5)
conanfile.py: Generator 'CMakeToolchain' calling 'generate()'
conanfile.py: CMakeToolchain generated: conan_toolchain.cmake
conanfile.py: Preset 'conan-default' added to CMakePresets.json. Invoke it manually using 'cmake --preset conan-default' if using CMake>=3.23
conanfile.py: If your CMake version is not compatible with CMakePresets (<3.23) call cmake like: 'cmake <path> -G "Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE=C:\work\src\myproject\build\conan_toolchain.cmake -DCMAKE_POLICY_DEFAULT_CMP0091=NEW'
conanfile.py: CMakeToolchain generated: CMakePresets.json
conanfile.py: CMakeToolchain generated: ..\CMakeUserPresets.json
conanfile.py: Generating aggregated env files
conanfile.py: Generated aggregated env files: ['conanbuild.sh', 'conanrun.sh']
Install finished successfully
Preset CMake variables:
CMAKE_BUILD_TYPE="Release"
CMAKE_TOOLCHAIN_FILE:FILEPATH="conan_toolchain.cmake"
TOOLCHAIN_PREFIX="C:/Program Files (x86)/Arm GNU Toolchain arm-none-eabi/12.2 mpacbti-rel1"
-- Using Conan toolchain: C:/work/src/myproject/build/conan_toolchain.cmake
-- The C compiler identification is GNU 12.2.1
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: C:/Program Files (x86)/Arm GNU Toolchain arm-none-eabi/12.2 mpacbti-rel1/bin/arm-none-eabi-gcc.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Conan: Target declared 'cmsis5::cmsis5'
-- Found cmsis5: 0.1.0 (found version "0.1.0")
-- Configuring done (1.7s)
-- Generating done (0.1s)
-- Build files have been written to: C:/work/src/myproject/build
[1/43] Building C object CMakeFiles/myproject.dir/Debug/src/appmain.c.obj
FAILED: CMakeFiles/myproject.dir/Debug/src/appmain.c.obj
C:\PROGRA~2\ARMGNU~1\12977F~1.2MP\bin\AR19DD~1.EXE -D_GLIBCXX_USE_CXX11_ABI=0 -DCMAKE_INTDIR=\"Debug\" -IC:/work/src/myproject/src -IC:/work/src/myproject/ra/fsp/inc -IC:/work/src/myproject/ra/fsp/inc/api -IC:/work/src/myproject/ra/fsp/inc/instances -IC:/work/src/myproject/ra_gen -IC:/work/src/myproject/ra_cfg/fsp_cfg/bsp -IC:/work/src/myproject/ra_cfg/fsp_cfg -mcpu=cortex-m23 -mthumb -O0 -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -Wunused -Wuninitialized -Wall -Wextra -Wmissing-declarations -Wconversion -Wpointer-arith -Wshadow -Wlogical-op -Waggregate-return -Wfloat-equal -g -gdwarf-4 -D_RENESAS_RA_ -D_RA_CORE=CM23 -std=c99 -MMD -MP -Og -g -MD -MT CMakeFiles/myproject.dir/Debug/src/appmain.c.obj -MF CMakeFiles\myproject.dir\Debug\src\appmain.c.obj.d -o CMakeFiles/myproject.dir/Debug/src/appmain.c.obj -c C:/work/src/myproject/src/appmain.c
In file included from C:/work/src/myproject/ra/fsp/inc/api/bsp_api.h:47,
from C:/work/src/myproject/ra_gen/hal_data.h:5,
from C:/work/src/myproject/src/hal.h:11,
from C:/work/src/myproject/src/appmain.c:1:
c:\work\src\myproject\ra\fsp\src\bsp\cmsis\device\renesas\include\renesas.h:42:11: fatal error: cmsis_compiler.h: No such file or directory
42 | #include "cmsis_compiler.h"
| ^~~~~~~~~~~~~~~~~~
compilation terminated.
ninja: build stopped: subcommand failed.
A quick possible hint is that when using a specific generator as
Ninja Multi-Config
it is necessary to tell Conan, with-c tools.cmake.cmaketoolchain:generator="Ninja Multi-Config"
, so things are aligned.
This gives me:
======== Input profiles ========
Profile host:
[settings]
arch=armv8.3
compiler=gcc
compiler.libcxx=libstdc++
compiler.version=13.2
os=baremetal
[conf]
tools.cmake.cmaketoolchain:generator=Ninja Multi-Config
tools.cmake.cmaketoolchain:user_toolchain=['C:\\work\\src\\myproject/gcc-toolchain.cmake']
Profile build:
[settings]
arch=armv8.3
compiler=gcc
compiler.libcxx=libstdc++
compiler.version=13.2
os=baremetal
[conf]
tools.cmake.cmaketoolchain:user_toolchain=['C:\\work\\src\\myproject/gcc-toolchain.cmake']
======== Computing dependency graph ========
Graph root
conanfile.py: C:\work\src\myproject\conanfile.py
Requirements
cmsis5/0.1.0#c5711ac2ca3283714557f93b4bd51fa7 - Cache
======== Computing necessary packages ========
Requirements
cmsis5/0.1.0#c5711ac2ca3283714557f93b4bd51fa7:da39a3ee5e6b4b0d3255bfef95601890afd80709#c3c71f623eb728469d6afcc66453dfaa - Cache
======== Installing packages ========
cmsis5/0.1.0: Already installed! (1 of 1)
======== Finalizing install (deploy, generators) ========
conanfile.py: Writing generators to C:\work\src\myproject\build
conanfile.py: Generator 'CMakeDeps' calling 'generate()'
conanfile.py: CMakeDeps necessary find_package() and targets for your CMakeLists.txt
find_package(cmsis5)
target_link_libraries(... cmsis5::cmsis5)
conanfile.py: Generator 'CMakeToolchain' calling 'generate()'
conanfile.py: CMakeToolchain generated: conan_toolchain.cmake
conanfile.py: Preset 'conan-default' added to CMakePresets.json. Invoke it manually using 'cmake --preset conan-default' 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 Multi-Config" -DCMAKE_TOOLCHAIN_FILE=C:\work\src\myproject\build\conan_toolchain.cmake -DCMAKE_POLICY_DEFAULT_CMP0091=NEW'
conanfile.py: CMakeToolchain generated: CMakePresets.json
conanfile.py: CMakeToolchain generated: ..\CMakeUserPresets.json
conanfile.py: Generating aggregated env files
conanfile.py: Generated aggregated env files: ['conanbuild.sh', 'conanrun.sh']
Install finished successfully
CMake Error: Could not read presets from C:/work/src/myproject:
"configuration" expected a string, got:
"configuration" expected a string, got:
CMake Error: Could not read presets from C:/work/src/myproject:
"configuration" expected a string, got:
"configuration" expected a string, got:
Some important thing:
Profile build:
[settings]
arch=armv8.3
compiler=gcc
compiler.libcxx=libstdc++
compiler.version=13.2
os=baremetal
[conf]
tools.cmake.cmaketoolchain:user_toolchain=['C:\\work\\src\\myproject/gcc-toolchain.cmake']
This is an incorrect "build" profile. The build profile will be your current machine, it will be os=Windows/Linux/Macos in most cases, not baremetal. And same with arch
and other settings, they must align with your current machine, typically something like the conan profile detect
OK, that was just a recent addition when doing my tests, I will remove it.
I read this page: https://docs.conan.io/2/tutorial/consuming_packages/cross_building_with_conan.html
If I understood correctly, this wouldn't affect the usability of the created package? I mean: if I cross-compile my source code on my CI environment (which uses Linux), it will still be usable from the developer's Windows machine, because the build profile doesn't affect the package id. It will just be used when deciding when using the requirements and build_requirements from the conanfile.py recipe. Is this correct?
If I understood correctly, this wouldn't affect the usability of the created package?
It might easily break the build and don't build correctly. Yes, the package_id
is independent of the "build" context in general, but the binary might not be correct if for some reason the "build" context is not correctly configured.
What is your question?
Disclaimer: I'm still a newbie both in CMake and Conan.
I'm working on migrating an embedded project to CMake + Conan.
In the first stage, I have created the CMakeLists, CMakeUserPresets, and gcc-toolchain.cmake files (without using Conan).
The gcc-toolchain files contain everything that's compiler-related and could be extracted from the project: the compiler to be used and the compiler flags when compiling and linking. The idea is to create one toolchain file for each compiler we're using and choose the more suitable one on a per-project basis.
Then I tried to extract some ARM headers (CMSIS5 stuff) in a Conan package and consume it from the main project. I was able to create it, but not to consume it, as the compiler isn't finding the header files (I'm using find_package() and target_link_libraries(), but the path isn't passed when invoking GCC).
But maybe before that, the problem is the Conan vs. custom toolchain files:
So already having a toolchain file, I can't use the one generated by Conan. But well... since in the conanfile.py we can choose to not generate the Conan toolchain file, I assumed that it isn't strictly necessary... or it is? The documentation states that the Conan toolchain file can be not created, so I assume that it isn't mandatory, yet I can't find in the documentation the info on how to do things without the Conan toolchain file. This confuses me a lot.
I won't write regarding the other things I tried to do, since I didn't really know what I was doing. For the moment, I'll just ask if someone can point me in the right direction regarding the toolchain files.
To summarize: can I use a Conan dependency without the Conan toolchain file? If not, is there a way to put "somewhere" my actual toolchain file so that it can be used with Conan?
I'm sorry for the confused post, it reflects the confusion I have in my head 😅
Have you read the CONTRIBUTING guide?