conan-io / conan

Conan - The open-source C and C++ package manager
https://conan.io
MIT License
8.29k stars 982 forks source link

[bug] Broken cmake project compilation "Conan 2.9.0" (Feature/auto compiler cl exe #16875) #17336

Closed theRedMercury closed 1 day ago

theRedMercury commented 4 days ago

Describe the bug

Hello,

Since Conan 2.9.0, our project compilation is broken.

Related to : https://github.com/conan-io/conan/pull/16875

[cmake] ======== Input profiles ========
[cmake] Profile host:
[cmake] [settings]
[cmake] arch=x86_64
[cmake] build_type=RelWithDebInfo
[cmake] compiler=msvc
[cmake] compiler.cppstd=20
[cmake] compiler.runtime=dynamic
[cmake] compiler.runtime_type=Release
[cmake] compiler.version=194
[cmake] os=Windows
[cmake] 
[cmake] Profile build:
[cmake] [settings]
[cmake] arch=x86_64
[cmake] build_type=RelWithDebInfo
[cmake] compiler=msvc
[cmake] compiler.cppstd=20
[cmake] compiler.runtime=dynamic
[cmake] compiler.runtime_type=Release
[cmake] compiler.version=194
[cmake] os=Windows

We are using conan to generate the build directory

And we call cmake (outside) the conan process. It’s work like a charm since conan 1. But we don’t know why, in conan_toolchain.cmake file section “'compilers' block“

set(CMAKE_C_COMPILER "cl") set(CMAKE_CXX_COMPILER "cl")

generate the CMake error.

CMake Error at source/unit-test/CMakeLists.txt:10 (project):
  The CMAKE_C_COMPILER:

    cl

  is not a full path and was not found in the PATH.  Perhaps the extension is
  missing?

  Tell CMake where to find the compiler by setting either the environment
  variable "CC" or the CMake cache entry CMAKE_C_COMPILER to the full path to
  the compiler, or to the compiler name if it is in the PATH.

CMake Error at source/unit-test/CMakeLists.txt:10 (project):
  The CMAKE_CXX_COMPILER:

    cl

  is not a full path and was not found in the PATH.  Perhaps the extension is
  missing?

  Tell CMake where to find the compiler by setting either the environment
  variable "CXX" or the CMake cache entry CMAKE_CXX_COMPILER to the full path
  to the compiler, or to the compiler name if it is in the PATH.

-- Configuring incomplete, errors occurred!

And we are in the x64 Native Tools CMD vs 2022

C:\Program Files\Microsoft Visual Studio\2022\Professional>cl
Microsoft (R) C/C++ Optimizing Compiler Version 19.42.34433 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

usage: cl [ option... ] filename... [ /link linkoption... ]

If we remove manually in the file conan_toolchain.cmake file, it’s work.

How to reproduce it

No response

memsharded commented 4 days ago

Hi @theRedMercury

Thanks for your report.

In theory the CMAKE_CXX_COMPILER is only set when necessary, for example, when the generator is Ninja, because when that happens, this is kind of necessary. The build also finds the compiler because an activation of the VS prompt (vcvars.bat) also happens at some point, either via Conan, or the IDE or CMake or something like that.

And what is confusing is that when you type it in the terminal, it is actually found, a bit unexpected.

I am a bit confused about the [cmake] in the logs, are you calling Conan from CMake? Are you doing it from the cmake-conan integration? In any of both cases, this shouldn't be an issue, because the toolchain or the presets are not really used at all, as the build is driven by CMake.

theRedMercury commented 3 days ago

Yes, it’s really confusing.

In fact we ask to Conan to generate everything in the build file with “conan install” cmd And after that, we run manually (in X64 Tool terminal or IDE env) :

"cmake.exe" -DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=TRUE -SC:/source -Bc:/build/RelWithDebInfo -G Ninja

We are using the CMakeDeps, CMakeToolchain with Ninja in the conanfile.py

ct = CMakeToolchain(self, generator="Ninja")
ct.generate()

The CMAKE_CXX_COMPILER is correctly define with the full cl path in (“CMakeCXXCompiler.cmake” & “CMakeCache.txt”) Visible with CMake gui :

image

Everything working great if I had manually this condition in the conan_toolchain.cmake (in conan 2.9.2)

########## 'compilers' block #############
if(NOT DEFINED CMAKE_C_COMPILER)
  set(CMAKE_C_COMPILER "cl")
endif()
if(NOT DEFINED CMAKE_CXX_COMPILER)
  set(CMAKE_CXX_COMPILER "cl")
endif()

And for the build, we run (also manually) :

"cmake.exe" --build c:/build/RelWithDebInfo --config RelWithDebInfo --target all
memsharded commented 3 days ago

Thanks for the feedback! I am trying to reproduce without success. This is what I am trying:

$ conan new cmake_lib
$ conan install . -c tools.cmake.cmaketoolchain:generator=Ninja
# This creates the conan_toolchain with the "cl" defined
$  .\build\Release\generators\conanbuild.bat
> conanvcvars.bat: Activating environment Visual Studio 17 - amd64 - winsdk_version=None - vcvars_ver=14.4
$ cmake . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release
$ cmake --build build

I am running it in a cmder and cmd terminals. I am thinking if it could be some misalignment in the VS prompt / vcvars.

Could you please try the steps above? If it works, maybe try to provide similar full steps that reproduce on your side so I can try here exactly the same thing? Thanks!

theRedMercury commented 3 days ago

I founded the issue.

In fact in our project we define in the CMakeLists.txt the project name like "project(mypkg CXX)”

But it’s a software and we have other projects defined in the cmake. And between the first project() and the second one, we call the conan_toolchain.cmake in the CMakeLists.txt file like this

include(build/Release/generators/conan_toolchain.cmake)
set(CMAKE_TOOLCHAIN_FILE "build/Release/generators/conan_toolchain.cmake")

The example is more understandable, in your case :

Edit the CMakeLists.txt before the conan install cmd

Compilation OK

cmake_minimum_required(VERSION 3.15)

include(build/Release/generators/conan_toolchain.cmake)
set(CMAKE_TOOLCHAIN_FILE "build/Release/generators/conan_toolchain.cmake")

# Project 1 ===
message(STATUS "CMAKE_CXX_COMPILER : ${CMAKE_CXX_COMPILER}")
project(mypkg CXX)

add_library(mypkg src/mypkg.cpp)
target_include_directories(mypkg PUBLIC include)

set_target_properties(mypkg PROPERTIES PUBLIC_HEADER "include/mypkg.h")
install(TARGETS mypkg)

Cmake Ninja NOT OK

cmake_minimum_required(VERSION 3.15)

#include(build/Release/generators/conan_toolchain.cmake)
#set(CMAKE_TOOLCHAIN_FILE "build/Release/generators/conan_toolchain.cmake")

# Project 1 ===
message(STATUS "CMAKE_CXX_COMPILER : ${CMAKE_CXX_COMPILER}")
project(mypkg CXX)

add_library(mypkg src/mypkg.cpp)
target_include_directories(mypkg PUBLIC include)

set_target_properties(mypkg PROPERTIES PUBLIC_HEADER "include/mypkg.h")
install(TARGETS mypkg)

# Include Conan generated toolchain file (No issue if put before project 1)
include(build/Release/generators/conan_toolchain.cmake)
set(CMAKE_TOOLCHAIN_FILE "build/Release/generators/conan_toolchain.cmake")

# Project 2 ===
message(STATUS "CMAKE_CXX_COMPILER : ${CMAKE_CXX_COMPILER}")
project(mypkg2 CXX)

add_library(mypkg2 src/mypkg.cpp)
target_include_directories(mypkg2 PUBLIC include)

set_target_properties(mypkg2 PROPERTIES PUBLIC_HEADER "include/mypkg.h")
install(TARGETS mypkg2)

Compilation OK

cmake_minimum_required(VERSION 3.15)

include(build/Release/generators/conan_toolchain.cmake)
set(CMAKE_TOOLCHAIN_FILE "build/Release/generators/conan_toolchain.cmake")

# Project 1 ===
message(STATUS "CMAKE_CXX_COMPILER : ${CMAKE_CXX_COMPILER}")
project(mypkg CXX)

add_library(mypkg src/mypkg.cpp)
target_include_directories(mypkg PUBLIC include)

set_target_properties(mypkg PROPERTIES PUBLIC_HEADER "include/mypkg.h")
install(TARGETS mypkg)

# Include Conan generated toolchain file (No issue if put before project 1)
#include(build/Release/generators/conan_toolchain.cmake)
#set(CMAKE_TOOLCHAIN_FILE "build/Release/generators/conan_toolchain.cmake")

# Project 2 ===
message(STATUS "CMAKE_CXX_COMPILER : ${CMAKE_CXX_COMPILER}")
project(mypkg2 CXX)

add_library(mypkg2 src/mypkg.cpp)
target_include_directories(mypkg2 PUBLIC include)

set_target_properties(mypkg2 PROPERTIES PUBLIC_HEADER "include/mypkg.h")
install(TARGETS mypkg2)
memsharded commented 2 days ago

include(build/Release/generators/conan_toolchain.cmake)

Ok this is indeed relevant. CMake toolchain files shouldn't be used with include() from CMakeLists.txt. Their main purpose is to be external and orthogonal, they should only be injected via cli args like -DCMAKE_TOOLCHAIN_FILE or via presets. For example in https://cmake.org/cmake/help/latest/variable/CMAKE_TOOLCHAIN_FILE.html

This variable is specified on the command line when cross-compiling with CMake.

More accurately, including a toolchain file after a call to project() is broken behavior

theRedMercury commented 1 day ago

Yes indeed, Thanks for the support 😊

I will close this issue.

memsharded commented 1 day ago

Thanks to you for the feedback! :)

Don't hesitate to re-open or create new tickets for any further question or issue you might have.