conan icon indicating copy to clipboard operation
conan copied to clipboard

[bug] CMakeDeps: `<name>_LIBRARIES` variable is not suitable for macros like `check_symbol_exists`

Open SpaceIm opened this issue 3 years ago • 5 comments

Environment Details (include every applicable attribute)

  • Operating System+version: macOS Monterey
  • Compiler+version: AppleClang 14
  • Conan version: 1.52.0
  • Python version: 3.10.6
  • cmake version: 3.24.2

Steps to reproduce (Include if Applicable)

CMakeLists.txt

cmake_minimum_required(VERSION 3.15)
project(test_check_symbol_exists LANGUAGES C)

find_package(zstd REQUIRED)

include(CheckSymbolExists)
set(CMAKE_REQUIRED_INCLUDES_SAVE ${CMAKE_REQUIRED_INCLUDES})
set(CMAKE_REQUIRED_LIBRARIES_SAVE ${CMAKE_REQUIRED_LIBRARIES})
list(PREPEND CMAKE_REQUIRED_INCLUDES ${zstd_INCLUDE_DIRS})
list(PREPEND CMAKE_REQUIRED_LIBRARIES ${zstd_LIBRARIES})
check_symbol_exists(ZSTD_decompressStream "zstd.h" ZSTD_RECENT_ENOUGH)
set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES_SAVE})
set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES_SAVE})

if(ZSTD_RECENT_ENOUGH)
    message(STATUS "Test succeeded")
else()
    message(FATAL_ERROR "Test failed")
endif()

test succeeds with cmake_find_package:

mkdir build1 && cd build1
conan install zstd/1.5.2@ -g CMakeToolchain -g cmake_find_package -c tools.cmake.cmaketoolchain:find_package_prefer_config="OFF"
cmake .. -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Release

test fails with CMakeDeps:

mkdir build2 && cd build2
conan install zstd/1.5.2@ -g CMakeToolchain -g CMakeDeps
cmake .. -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Release

CMAKE_REQUIRED_INCLUDES works fine here, but not CMAKE_REQUIRED_LIBRARIES, because zstd_LIBRARIES is set to zstd imported target instead of full paths of all libraries. According to CMake documentation, check_c_source_compiles allows imported targets in CMAKE_REQUIRED_LIBRARIES, but they don't say anything for check_symbol_exists.

It's quite annoying for conan v2 migration of several CCI recipes.

Logs (Executed commands with output) (Include/Attach if Applicable)

CMakeError.log of CMakeDeps test:

Compiling the C compiler identification source file "CMakeCCompilerId.c" failed.
Compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc
Build flags: ;;;;-m64
Id flags:

The output was:
1
ld: library not found for -lSystem
clang: error: linker command failed with exit code 1 (use -v to see invocation)


Determining if the ZSTD_decompressStream exist failed with the following output:
Change Dir: /Users/spaceim/Documents/Personnel/test_check_symbol/build2/CMakeFiles/CMakeTmp

Run Build Command(s):/usr/bin/make -f Makefile cmTC_ed876/fast && /Applications/Xcode.app/Contents/Developer/usr/bin/make  -f CMakeFiles/cmTC_ed876.dir/build.make CMakeFiles/cmTC_ed876.dir/build
Building C object CMakeFiles/cmTC_ed876.dir/CheckSymbolExists.c.o
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc  -I/Users/spaceim/.conan/data/zstd/1.5.2/_/_/package/258f9d253d0e975fcb3ab38da19bbea0bc9bf506/include -m64  -arch x86_64 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.3.sdk -MD -MT CMakeFiles/cmTC_ed876.dir/CheckSymbolExists.c.o -MF CMakeFiles/cmTC_ed876.dir/CheckSymbolExists.c.o.d -o CMakeFiles/cmTC_ed876.dir/CheckSymbolExists.c.o -c /Users/spaceim/Documents/Personnel/test_check_symbol/build2/CMakeFiles/CMakeTmp/CheckSymbolExists.c
Linking C executable cmTC_ed876
/Applications/CMake.app/Contents/bin/cmake -E cmake_link_script CMakeFiles/cmTC_ed876.dir/link.txt --verbose=1
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc -m64  -arch x86_64 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.3.sdk -Wl,-search_paths_first -Wl,-headerpad_max_install_names -m64  CMakeFiles/cmTC_ed876.dir/CheckSymbolExists.c.o -o cmTC_ed876
Undefined symbols for architecture x86_64:
  "_ZSTD_decompressStream", referenced from:
      _main in CheckSymbolExists.c.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[1]: *** [cmTC_ed876] Error 1
make: *** [cmTC_ed876/fast] Error 2


File /Users/spaceim/Documents/Personnel/test_check_symbol/build2/CMakeFiles/CMakeTmp/CheckSymbolExists.c:
/* */
#include <zstd.h>

int main(int argc, char** argv)
{
  (void)argv;
#ifndef ZSTD_decompressStream
  return ((int*)(&ZSTD_decompressStream))[argc];
#else
  (void)argc;
  return 0;
#endif
}

SpaceIm avatar Sep 22 '22 21:09 SpaceIm

similar issue as https://github.com/conan-io/conan/issues/12012

SpaceIm avatar Nov 01 '22 20:11 SpaceIm

The CMake documentation specifies that targets are actually a valid input for anything that relies on try_compile, including check_symbol_exists. Docs here: https://cmake.org/cmake/help/latest/command/try_compile.html#options

The problem here is that the targets generated by CMakeDeps require a build type to be set (CMAKE_BUILD_TYPE for single config generators) - but the temporary CMake project that is created by try_compile, does not have any configuration set, which causes the issues.

A possible solution is to simply tell CMake to forward the current configuration to the try_compile generated projects: https://cmake.org/cmake/help/latest/variable/CMAKE_TRY_COMPILE_CONFIGURATION.html#variable:CMAKE_TRY_COMPILE_CONFIGURATION - in a recipe this could be done via:

tc.cache_variables["CMAKE_TRY_COMPILE_CONFIGURATION"] = str(self.settings.build_type)

Alternatively, this fix in upstream CMake https://gitlab.kitware.com/cmake/cmake/-/merge_requests/8016 might help - I believe it made it to CMake 3.26. I still need to test if it solves this particular issue, as the underlying cause has to do with the targets generated by CMakeDeps having gen-ex conditionals that depend on the build type.

jcar87 avatar Nov 08 '23 10:11 jcar87

I can test with dcmtk.

SpaceIm avatar Nov 08 '23 21:11 SpaceIm

It doesn't seem to work. I've tested in dcmtk recipe:

  • I've removed current workaround for this issue in dcmtk recipe: https://github.com/conan-io/conan-center-index/blob/master/recipes/dcmtk/all/conanfile.py#L164-L229
  • And added tc.cache_variables["CMAKE_TRY_COMPILE_CONFIGURATION"] = str(self.settings.build_type)

But still get this error during CMake configuration (macOS x86_64/Release/all shared/apple-clang 15/CMake 3.27.7/conan 2.0.13/Ninja generator):

-- Looking for prototype of SSL_CTX_get0_param
CMake Error at /Users/spaceim/.conan2/p/b/dcmtk278ca8b211711/b/build/Release/CMakeFiles/CMakeTmp/CMakeLists.txt:25 (target_link_libraries):
  Target "cmTC_4d7c0" links to:

    openssl::openssl

  but the target was not found.  Possible reasons include:

    * There is a typo in the target name.
    * A find_package call is missing for an IMPORTED target.
    * An ALIAS target is missing.



CMake Error at CMake/CheckFunctionWithHeaderExists.cmake:30 (try_compile):
  Failed to generate test project build system.
Call Stack (most recent call first):
  CMake/dcmtkPrepare.cmake:671 (CHECK_FUNCTIONWITHHEADER_EXISTS)
  CMakeLists.txt:38 (include)

SpaceIm avatar Nov 08 '23 21:11 SpaceIm

Adding CMAKE_TRY_COMPILE_CONFIGURATION very clearly fixed the try_compile() issues with OpenSSL symbol detection in https://github.com/conan-io/conan-center-index/pull/21389.

I'll be adding this workaround just in case for any recipes that make use of compilation tests with CMAKE_REQUIRED_LIBRARIES in the future.

valgur avatar Jan 25 '24 08:01 valgur