conan-io / conan

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

[bug] Generating a Release project requires building in Debug. Can't find library without changing macros. #15985

Open Jaskowicz1 opened 3 months ago

Jaskowicz1 commented 3 months ago

Describe the bug

OS: Windows 11 Compiler: Visual Studio 17 2022 (MSVC 19.38.33130.0, MSBuild version 17.8.3+195e7f5a3) Conan Ver: 2.2.2 Conan profiles: default

When creating a test project to use D++ with Conan, I end up having to build in Debug even though I setup the project for Release (I really don't know how to word this any other way, it's massively confusing). I also have to remove part of cmakedeps_macros.cmake to even let Conan find D++, because it just can't find it?

How to reproduce it

Step 1) Clone D++ from an in-progress PR: https://github.com/MikeRavenelle/DPP Step 2) Switch to the conan_support branch and pull it. Step 3) Run cd library-conan Step 4) Change def generate(self) in the conanfile.py to:

def generate(self):
        deps = CMakeDeps(self)
        deps.generate()
        tc = CMakeToolchain(self)
        tc.cache_variables["CONAN_EXPORTED"] = True
        tc.cache_variables["BUILD_VOICE_SUPPORT"] = True
        tc.cache_variables["DPP_BUILD_TEST"] = False
        tc.cache_variables["BUILD_SHARED_LIBS"] = False
        tc.generate()

Yes, this step is required. They haven't updated their PR to include this yet, so without BUILD_SHARED_LIBS as false, Conan will double include ZLib (I have no idea why). Step 5) Commit it so Conan doesn't shout about the package being dirty (you can't push it, but this just shuts up Conan). Step 6) Run conan create . Step 7) Let Conan do it's thing Step 8) Go to a different folder (for now, let's say Documents) and make a new sample project (mkdir test_proj will do) with the following: CMakeLists.txt, conanfile.txt, and main.cpp. These files should have the following contents: CMakeLists.txt:

cmake_minimum_required(VERSION 3.22)
project(testproj)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_PREFIX_PATH "${CMAKE_CURRENT_LIST_DIR}/build")

find_package(dpp)

add_executable(testproj main.cpp)
target_link_libraries(${PROJECT_NAME} dpp::dpp)

conanfile.txt:

[requires]
dpp/10.0.29

[generators]
CMakeDeps
CMakeToolchain

main.cpp:

#include <dpp/dpp.h>

const std::string BOT_TOKEN = "Discord bot token here";

int main() {
    dpp::cluster bot(BOT_TOKEN);

    bot.on_log(dpp::utility::cout_logger());

    bot.on_slashcommand([](const dpp::slashcommand_t& event) {
        if (event.command.get_command_name() == "ping") {
            event.reply("Pong!");
        }
    });

    bot.on_ready([&bot](const dpp::ready_t& event) {
        if (dpp::run_once<struct register_bot_commands>()) {
            bot.global_command_create(dpp::slashcommand("ping", "Ping pong!", bot.me.id));
        }
    });

    bot.start(dpp::st_wait);
}

Step 9) Run conan install . --output-folder=build --build=missing -s build_type=Release. Step 10) Run cd build. Step 11) Run cmake .. -G "Visual Studio 17 2022" -DCMAKE_TOOLCHAIN_FILE="conan_toolchain.cmake" -DCMAKE_BUILD_TYPE=Release and notice how dpp can't be found (Please address this too!).

The next step addresses how to fix this issue in a very hacky and bad way, but I assume might be the cause of the whole Release makes Debug and so on.

Step 12) Edit cmakedeps_macros.cmake and navigate to line 23. Strip the find_library down to find_library(CONAN_FOUND_LIBRARY NAMES ${_LIBRARY_NAME} PATHS ${package_libdir}) and move the entire if statement outside the if statement. It should look like this below:

message(VERBOSE "Conan: Library ${_LIBRARY_NAME} found ${CONAN_FOUND_LIBRARY}")

        # Create a micro-target for each lib/a found
        # Allow only some characters for the target name
        string(REGEX REPLACE "[^A-Za-z0-9.+_-]" "_" _LIBRARY_NAME ${_LIBRARY_NAME})
        set(_LIB_NAME CONAN_LIB::${package_name}_${_LIBRARY_NAME}${config_suffix})

        if(is_host_windows AND library_type STREQUAL "SHARED")
                # Store and reset the variable, so it doesn't leak
                set(_OLD_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
                set(CMAKE_FIND_LIBRARY_SUFFIXES .dll ${CMAKE_FIND_LIBRARY_SUFFIXES})
                find_library(CONAN_SHARED_FOUND_LIBRARY NAMES ${_LIBRARY_NAME} PATHS ${package_bindir}
                        NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)
                set(CMAKE_FIND_LIBRARY_SUFFIXES ${_OLD_CMAKE_FIND_LIBRARY_SUFFIXES})
                if(NOT CONAN_SHARED_FOUND_LIBRARY)
                        message(STATUS "Cannot locate shared library: ${_LIBRARY_NAME}")
                        message(DEBUG "DLL library not found, creating UNKNOWN IMPORTED target")
                        if(NOT TARGET ${_LIB_NAME})
                                add_library(${_LIB_NAME} UNKNOWN IMPORTED)
                        endif()
                        set_target_properties(${_LIB_NAME} PROPERTIES IMPORTED_LOCATION${config_suffix} ${CONAN_FOUND_LIBRARY})
                else()
                        if(NOT TARGET ${_LIB_NAME})
                                add_library(${_LIB_NAME} SHARED IMPORTED)
                        endif()
                        set_target_properties(${_LIB_NAME} PROPERTIES IMPORTED_LOCATION${config_suffix} ${CONAN_SHARED_FOUND_LIBRARY})
                        set_target_properties(${_LIB_NAME} PROPERTIES IMPORTED_IMPLIB${config_suffix} ${CONAN_FOUND_LIBRARY})
                        message(DEBUG "Found DLL and STATIC at ${CONAN_SHARED_FOUND_LIBRARY}, ${CONAN_FOUND_LIBRARY}")
                endif()
                unset(CONAN_SHARED_FOUND_LIBRARY CACHE)
        else()
                if(NOT TARGET ${_LIB_NAME})
                        # library_type can be STATIC, still UNKNOWN (if no package type available in the recipe) or SHARED (but no windows)
                        add_library(${_LIB_NAME} ${library_type} IMPORTED)
                endif()
                message(DEBUG "Created target ${_LIB_NAME} ${library_type} IMPORTED")
                set_target_properties(${_LIB_NAME} PROPERTIES IMPORTED_LOCATION${config_suffix} ${CONAN_FOUND_LIBRARY} IMPORTED_NO_SONAME ${no_soname_mode})
        endif()
        list(APPEND _out_libraries_target ${_LIB_NAME})
        message(VERBOSE "Conan: Found: ${CONAN_FOUND_LIBRARY}")

Step 13) Re-run cmake .. -G "Visual Studio 17 2022" -DCMAKE_TOOLCHAIN_FILE="conan_toolchain.cmake" -DCMAKE_BUILD_TYPE=Release and notice how there's no issues anymore. Step 14) Run cd .. Step 15) Run cmake --build build --config Release and notice the LINK : fatal error LNK1181: cannot open input file 'CONAN_FOUND_LIBRARY-NOTFOUND.obj' error. Step 16) Run cmake --build build --config Debug and notice no error (However, everything we did, was for release!). Step 17) Run cd build, cd Debug. Step 18) Run ls (or whatever the equivelent is for command prompt, I use powershell) and notice how all the files are there!

Jaskowicz1 commented 3 months ago

Just to add, if you get an abort with an invalid token (if you manage to figure it out or whatnot) when running the .exe, that's normal. Put a try catch around the bot.start() if you would rather not get an abort.

Jaskowicz1 commented 3 months ago

Another note to add, Conan does generate release versions of all the requirements too. image So it's even more confusing why Debug works here.

If you flip Release for Debug and Debug for Release as you follow the steps, you'll get the same outcome (but ofc flipped so binaries will be in Release).

memsharded commented 3 months ago

Hi @Jaskowicz1

Thanks for your report, I am having a look.

I also have some feedback about the branch and the conanfile.py inside the library-conan, where should I report it?

Quick feedback about:

Re-run cmake .. -G "Visual Studio 17 2022" -DCMAKE_TOOLCHAIN_FILE="conan_toolchain.cmake" -DCMAKE_BUILD_TYPE=Release

VS is a multi-config generator, and as such CMAKE_BUILD_TYPE shouldn't be neither defined nor used. This might be related to the issue, I am building the project, but if you can try to drop it and try again to see if it helps, that would be great too.

Jaskowicz1 commented 3 months ago

Thank you for taking a look, @memsharded !

I also have some feedback about the branch and the conanfile.py inside the library-conan, where should I report it?

https://github.com/brainboxdotcc/DPP/pull/1066 would be the best place! That way the feedback is directly on the PR!

VS is a multi-config generator, and as such CMAKE_BUILD_TYPE shouldn't be neither defined nor used. This might be related to the issue, I am building the project, but if you can try to drop it and try again to see if it helps, that would be great too.

I'll certainly give another run without to see what happens!

memsharded commented 3 months ago

Some issues that I am seeing:

Likewise:

-- Installing: C:/Users/.../.conan2/p/b/dpp2166487df2998/p/lib/dpp-10.0/dpp.lib

So something like:

def package_info(self):
     self.cpp_info.includedirs = ["include/dpp-10.0"]
     self.cpp_info.libdirs= ["lib/dpp-10.0"]

I'd suggest to have a look to https://docs.conan.io/2/tutorial/creating_packages/define_package_information.html

Also, Conan has a built-in functionality, the test_package that automatically runs this check without having to have another separate project to test that it has been correctly packaged. Please check https://docs.conan.io/2/tutorial/creating_packages/test_conan_packages.html. You can start from the conan new cmake_lib -d name=mypkg -d version=0.1 to have a fully working package and test_package.