microsoft / vcpkg

C++ Library Manager for Windows, Linux, and MacOS
MIT License
22.16k stars 6.16k forks source link

[wxwidgets] With VS2019 solution generated by cmake in debug mode, release version of wx is used #18066

Closed playgithub closed 2 years ago

playgithub commented 3 years ago

Describe the bug With VS2019 solution generated by cmake in debug mode, release version of wx is used

Environment

To Reproduce Steps to reproduce the behavior:

  1. git clone https://github.com/playgithub/wxCharts.git
  2. use cmake or cmake-gui to generate a VS2019 solution (x64/debug/cpp17)

triplet file x64-windows-cpp17.cmake

set(VCPKG_TARGET_ARCHITECTURE x64)
set(VCPKG_CRT_LINKAGE dynamic)
set(VCPKG_LIBRARY_LINKAGE dynamic)
set(VCPKG_CXX_FLAGS "/std:c++17")
set(VCPKG_C_FLAGS "/std:c17")

Expected behavior wxCharts uses debug version of wxWidgets

Additional context You can see link dependencies of the project, it depends on the release version of wxWidgets. When I build a native VS2019 project that depends on wxWidgets in vcpkg, everything is ok. So it might be something in CMakeLists.txt for wxCharts leads to the problem.

dg0yt commented 3 years ago

Is this different from #18061?

playgithub commented 3 years ago

Is this different from #18061?

The same problem. While wxCharts depending on several libs in vcpkg, only wxWidgets used an unexpected lib (i.e. release instead of debug), so I post it again with more info. I've closed that issue. Thanks

playgithub commented 3 years ago

When I set wxWidgets_CONFIGURATION to mswud in cmake-gui and configure agian, it is reset to mswu.


To simplify:

set(VCPKG_ROOT "paht/to/vcpkg/scripts/buildsystems/vcpkg.cmake" CACHE PATH "")
set(CMAKE_TOOLCHAIN_FILE ${VCPKG_ROOT})

cmake_minimum_required(VERSION 3.12)

project(TestCMake)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "" FORCE) 
set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "")
set(VCPKG_TARGET_TRIPLET "x64-windows-cpp17" CACHE STRING "Set vcpkg triplet" FORCE)

# wxwidgets
find_package(wxWidgets REQUIRED COMPONENTS core base)
include(${wxWidgets_USE_FILE})

After cmake configure, the depdencies are as below.

LZMA_LIBRARIES optimized;path/to/vcpkg/installed/x64-windows-cpp17/lib/lzma.lib;debug;path/to/vcpkg/installed/x64-windows-cpp17/debug/lib/lzmad.lib
...
WX_Base path/to/vcpkg/installed/x64-windows-cpp17/lib/wxbase31u.lib
...

Every lib (e.g. LZMA_LIBRARIES) excpet wxWidgets (e.g. WX_Base) is OK, why?

playgithub commented 3 years ago

@JonLiu1993 I've tried the offical triplet: x64-windows, it has the problem.

playgithub commented 3 years ago

@NancyLi1013 I also tried the offical wxWidgets sample: minial, with only one cpp file and one native CMakelists.txt. It got the same problem. Sample: TestWxMinimal.zip

NancyLi1013 commented 3 years ago

Thanks for your information. I will try to build your project on my machine @playgithub.

NancyLi1013 commented 3 years ago

@playgithub

Seems you missed some files in your project sample. There is no sample.rc in TestWxMinimal.zip.

Edit: After comment this part out, I can build it successfully on my machine.

#if(WIN32)
#    # Include a RC file for windows
#    list(APPEND SRC_FILES ../sample.rc)
#elseif(APPLE)
#    # Add an icon for the apple .app file
#    list(APPEND SRC_FILES ../../src/osx/carbon/wxmac.icns)
#endif()

Here is the build result from my machine:

PS F:\latest\vcpkg\cprtest\build> cmake .. -G "Visual Studio 16 2019" -A "x64" -DCMAKE_BUILD_TYPE=debug
-- Selecting Windows SDK version 10.0.19041.0 to target Windows 10.0.19043.
-- The C compiler identification is MSVC 19.28.29915.0
-- The CXX compiler identification is MSVC 19.28.29915.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/VC/Tools/MSVC/14.28.29910/bin/Hostx64/x64/cl.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/VC/Tools/MSVC/14.28.29910/bin/Hostx64/x64/cl.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Found wxWidgets: F:/latest/vcpkg/installed/x64-windows/lib/wxmsw31u_core.lib;F:/latest/vcpkg/installed/x64-windows/lib/wxbase31u.lib;winmm;comctl32;uuid;oleacc;uxtheme;rpcrt4;shlwapi;version;wsock32 (found suitable version "3.1.5", minimum required is "3.1") found components: core base missing components: png tiff jpeg zlib regex expat
-- Looking for pthread.h
-- Looking for pthread.h - not found
-- Found Threads: TRUE
-- Found JPEG: optimized;F:/latest/vcpkg/installed/x64-windows/lib/jpeg.lib;debug;F:/latest/vcpkg/installed/x64-windows/debug/lib/jpegd.lib (found version "62")
-- Found ZLIB: optimized;F:/latest/vcpkg/installed/x64-windows/lib/zlib.lib;debug;F:/latest/vcpkg/installed/x64-windows/debug/lib/zlibd.lib (found version "1.2.11")
-- Configuring done
CMake Warning (dev) in CMakeLists.txt:
  Policy CMP0043 is not set: Ignore COMPILE_DEFINITIONS_<Config> properties.
  Run "cmake --help-policy CMP0043" for policy details.  Use the cmake_policy
  command to set the policy and suppress this warning.
This warning is for project developers.  Use -Wno-dev to suppress it.

-- Generating done
-- Build files have been written to: F:/latest/vcpkg/cprtest/build
PS F:\latest\vcpkg\cprtest\build>
PS F:\latest\vcpkg\cprtest\build> cmake --build .
Microsoft (R) Build Engine version 16.9.0+5e4b48a27 for .NET Framework
Copyright (C) Microsoft Corporation. All rights reserved.

  Checking Build System
  Building Custom Rule F:/latest/vcpkg/cprtest/CMakeLists.txt
  minimal.cpp
  minimal.vcxproj -> F:\latest\vcpkg\cprtest\build\Debug\minimal.exe
  Building Custom Rule F:/latest/vcpkg/cprtest/CMakeLists.txt

Can you provide your error info here?

playgithub commented 3 years ago

-- Found wxWidgets: F:/latest/vcpkg/installed/x64-windows/lib/wxmsw31u_core.lib;F:/latest/vcpkg/installed/x64-windows/lib/wxbase31u.lib;winmm;comctl32;uuid;oleacc;uxtheme;rpcrt4;shlwapi;version;wsock32 (found suitable version "3.1.5", minimum required is "3.1") found components: core base missing components: png tiff jpeg zlib regex expat

The ouput has shown the same problem as I do, see the line below,

-- Found wxWidgets: F:/latest/vcpkg/installed/x64-windows/lib/wxmsw31u_core.lib;F:/latest/vcpkg/installed/x64-windows/lib/wxbase31u.lib;winmm;comctl32;uuid;oleacc;uxtheme;rpcrt4;shlwapi;version;wsock32 (found suitable version "3.1.5", minimum required is "3.1") found components: core base missing components: png tiff jpeg zlib regex expat

For example, it uses wxbase31u.lib instead of wxbase31ud.lib, it is the problem.

copymark commented 3 years ago

Having the same problem. My app has \MTd in Debug but it takes the wxWidgets libraries from release that do have \MT as Runtime.

playgithub commented 3 years ago

It seems that with FindwxWidgets.cmake, debug version can not be found.

JackBoosY commented 3 years ago

@playgithub FindwxWidgets.cmake should be provided by cmake.

playgithub commented 3 years ago

@playgithub FindwxWidgets.cmake should be provided by cmake.

FindwxWidgets.cmake works, but found the wrong version (should be debug version instead of release version) on Windows

JackBoosY commented 3 years ago

The real problem is cmake expects debug and release to be installed in the same path, which is inconsistent with the rules of vcpkg: In Findwxwidgets.cmake

      foreach(CFG mswunivud mswunivd mswud mswd mswunivu mswuniv mswu msw qt qtd qtu qtud)
        set(WX_${CFG}_FOUND FALSE)
        if(EXISTS ${WX_LIB_DIR}/${CFG})
          list(APPEND WX_CONFIGURATION_LIST ${CFG})
          set(WX_${CFG}_FOUND TRUE)
          set(WX_CONFIGURATION ${CFG})
        endif()
      endforeach()
      DBG_MSG_V("WX_CONFIGURATION_LIST=${WX_CONFIGURATION_LIST}")
...
        # If release config selected, and both release/debug exist.
        if(WX_${wxWidgets_CONFIGURATION}d_FOUND)
          option(wxWidgets_USE_REL_AND_DBG
            "Use release and debug configurations?" TRUE)
          set(WX_USE_REL_AND_DBG ${wxWidgets_USE_REL_AND_DBG})
        else()
          # If the option exists (already in cache), force it false.
          if(wxWidgets_USE_REL_AND_DBG)
            set(wxWidgets_USE_REL_AND_DBG FALSE CACHE BOOL
              "No ${wxWidgets_CONFIGURATION}d found." FORCE)
          endif()
          set(WX_USE_REL_AND_DBG FALSE)
        endif()
...
  macro(WX_SET_LIBRARIES _LIBS _DBG)
    DBG_MSG_V("Looking for ${${_LIBS}}")
    message("WX_USE_REL_AND_DBG: ${WX_USE_REL_AND_DBG}")
    if(WX_USE_REL_AND_DBG)
      foreach(LIB ${${_LIBS}})
        DBG_MSG_V("Searching for ${LIB} and ${LIB}d")
        DBG_MSG_V("WX_${LIB}  : ${WX_${LIB}}")
        DBG_MSG_V("WX_${LIB}d : ${WX_${LIB}d}")
        if(WX_${LIB} AND WX_${LIB}d)
          DBG_MSG_V("Found ${LIB} and ${LIB}d")
          list(APPEND wxWidgets_LIBRARIES
            debug ${WX_${LIB}d} optimized ${WX_${LIB}}
            )
          set(wxWidgets_${LIB}_FOUND TRUE)
        elseif(NOT wxWidgets_FIND_REQUIRED_${LIB})
          DBG_MSG_V("- ignored optional missing WX_${LIB}=${WX_${LIB}} or WX_${LIB}d=${WX_${LIB}d}")
        else()
          DBG_MSG_V("- not found due to missing WX_${LIB}=${WX_${LIB}} or WX_${LIB}d=${WX_${LIB}d}")
          set(wxWidgets_FOUND FALSE)
        endif()
      endforeach()
    else()
      foreach(LIB ${${_LIBS}})
        DBG_MSG_V("Searching for ${LIB}${_DBG}")
        DBG_MSG_V("WX_${LIB}${_DBG} : ${WX_${LIB}${_DBG}}")
        if(WX_${LIB}${_DBG})
          DBG_MSG_V("Found ${LIB}${_DBG}")
          list(APPEND wxWidgets_LIBRARIES ${WX_${LIB}${_DBG}})
          set(wxWidgets_${LIB}_FOUND TRUE)
        elseif(NOT wxWidgets_FIND_REQUIRED_${LIB})
          DBG_MSG_V("- ignored optional missing WX_${LIB}${_DBG}=${WX_${LIB}${_DBG}}")
        else()
          DBG_MSG_V("- not found due to missing WX_${LIB}${_DBG}=${WX_${LIB}${_DBG}}")
          set(wxWidgets_FOUND FALSE)
        endif()
      endforeach()
    endif()
...
dg0yt commented 3 years ago

No way to pass the right combination of {WX,wxWidgets}_{ROOT,LIB}_DIR for debug?

JackBoosY commented 3 years ago

@dg0yt As you can see, the search paths for debug and release libraries are both ${WX_LIB_DIR}, and they are searched in the same query, and cmake does NOT distinguish between debug and release paths, which makes us powerless: we are unable to patch Findwxwidgets.cmake that provided by cmake. The only thing that can be done is to export all its cmake configuration files.

dg0yt commented 3 years ago

@JackBoosY Is the problem handling multi-config cmake? vcpkg-cmake-wrapper.cmake does know the single actual build type, so it could set different values for debug, in the same way vcpkg.cmake does that for CMAKE_PREFIX_PATH etc.

JackBoosY commented 3 years ago

@dg0yt Yes the wrapper can set that, but it will only call find_package(wxwidgets) once, which means wxWidgets_USE_REL_AND_DBG will always be OFF.

Please see the source code above.

dg0yt commented 3 years ago

... means wxWidgets_USE_REL_AND_DBG will always be OFF.

Please see the source code above.

I even looked into the full module source code... {WX,wxWidgets}_USE_REL_AND_DBG isn't even documented, despite its age (15 years!). I see that it takes care of tagging debug and optimized variants in wxWidgets_LIBRARIES. Is this mandatory?

playgithub commented 3 years ago

I even looked into the full module source code... {WX,wxWidgets}_USE_REL_AND_DBG isn't even documented, despite its age (15 years!). I see that it takes care of tagging debug and optimized variants in wxWidgets_LIBRARIES. Is this mandatory?

tags like debug and optimized are old grammar of cmake. For FindWxWidgets.cmake:

In fact, I'm using Linux now, really developer friendly. BTW, I'm reading "Professional CMake" by Craig Scott, hope enough cmake knowledge helps later.

JackBoosY commented 3 years ago

I'm trying to export all the wxwidgets component targets and will make a PR to the upstream.

playgithub commented 3 years ago

@JackBoosY Maybe it is not a problem of port wxwidgets, because only after recent updates of vcpkg (i.e. git pull vcpkg repo), my project can't run because debug version of app is trying to find release version of wx. One possible thing is that recent version is downloading vcpkg.exe instead of build it from source. I don't know if this is a policy for microsoft to make some lib hard to use.

playgithub commented 3 years ago

@JackBoosY The problem about wxwidgets is really blocking my work. Is it in progress?

JackBoosY commented 3 years ago

@playgithub WIP in https://github.com/microsoft/vcpkg/pull/18580 and https://github.com/microsoft/vcpkg/pull/17111

playgithub commented 3 years ago

@playgithub WIP in #18580 and #17111

A lot of work, thanks.

I just don't understand why it became so hard for a mature lib like wx. I'm going to learn about it.

JackBoosY commented 3 years ago

Please keep this issue open until we fix that.

playgithub commented 2 years ago

@JackBoosY If it is solved, please close it. I'm not using vcpkg now, because of https://github.com/microsoft/vcpkg/commit/aa60b7efa56a83ead743718941d8b320ef4a05af

Be-ing commented 2 years ago

We seem to be stumbling on this issue too in Tenacity with a very puzzling link error we've been trying to figure out for a few days with CMAKE_BUILD_TYPE=Debug with MSVC. If you look closely at the paths of the libraries, the debug libraries are used for all the libraries from vcpkg except wxWidgets:

LINK Pass 1: command "C:\PROGRA~2\MICROS~1\2019\ENTERP~1\VC\Tools\MSVC\1429~1.300\bin\Hostx64\x64\link.exe /nologo libraries\lib-string-utils\CMakeFiles\lib-string-utils.dir\UrlEncode.cpp.obj libraries\lib-string-utils\CMakeFiles\lib-string-utils.dir\UrlDecode.cpp.obj libraries\lib-string-utils\CMakeFiles\lib-string-utils.dir\CodeConversions.cpp.obj libraries\lib-string-utils\CMakeFiles\lib-string-utils.dir\DateTimeConversions.cpp.obj /out:shared\Debug\lib-string-utils.dll /implib:libraries\lib-string-utils\lib-string-utils.lib /pdb:shared\Debug\lib-string-utils.pdb /dll /version:0.0 /machine:x64 /debug /INCREMENTAL vcpkg_installed\x64-windows\lib\wxmsw31u_adv.lib vcpkg_installed\x64-windows\lib\wxbase31u.lib vcpkg_installed\x64-windows\lib\wxmsw31u_core.lib vcpkg_installed\x64-windows\lib\wxmsw31u_html.lib vcpkg_installed\x64-windows\lib\wxmsw31u_qa.lib vcpkg_installed\x64-windows\lib\wxbase31u_xml.lib vcpkg_installed\x64-windows\lib\wxbase31u_net.lib winmm.lib comctl32.lib uuid.lib oleacc.lib uxtheme.lib rpcrt4.lib shlwapi.lib version.lib wsock32.lib vcpkg_installed\x64-windows\debug\lib\tiffd.lib vcpkg_installed\x64-windows\debug\lib\lzmad.lib vcpkg_installed\x64-windows\debug\lib\jpegd.lib vcpkg_installed\x64-windows\lib\libexpat.lib vcpkg_installed\x64-windows\debug\lib\libpng16d.lib vcpkg_installed\x64-windows\debug\lib\zlibd.lib kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib /MANIFEST /MANIFESTFILE:libraries\lib-string-utils\CMakeFiles\lib-string-utils.dir/intermediate.manifest libraries\lib-string-utils\CMakeFiles\lib-string-utils.dir/manifest.res" failed (exit code 1120) with the following output:
   Creating library libraries\lib-string-utils\lib-string-utils.lib and object libraries\lib-string-utils\lib-string-utils.exp
DateTimeConversions.cpp.obj : error LNK2019: unresolved external symbol "__declspec(dllimport) public: __cdecl wxString::const_iterator::~const_iterator(void)" (__imp_??1const_iterator@wxString@@QEAA@XZ) referenced in function "bool __cdecl audacity::ParseRFC822Date(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &,class std::chrono::time_point<struct std::chrono::system_clock,class std::chrono::duration<__int64,struct std::ratio<1,10000000> > > *)" (?ParseRFC822Date@audacity@@YA_NAEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@PEAV?$time_point@Usystem_clock@chrono@std@@V?$duration@_JU?$ratio@$00$0JIJGIA@@std@@@23@@chrono@3@@Z)
shared\Debug\lib-string-utils.dll : fatal error LNK1120: 1 unresolved externals

CMAKE_BUILD_TYPE=RelWithDebInfo works fine.

Be-ing commented 2 years ago

I'm trying to export all the wxwidgets component targets and will make a PR to the upstream.

That would be great. I hacked together an INTERFACE target in the application's CMakeLists.txt so I don't have to deal with setting the wxWidgets_DEFINITIONS. There are several separate targets in this application that link wxWidgets. With this hack, I can just target_link_libraries the INTERFACE target:

if(NOT TARGET wxWidgets::wxWidgets)
  add_library(wxWidgets::wxWidgets INTERFACE IMPORTED)
  target_link_libraries(wxWidgets::wxWidgets INTERFACE ${wxWidgets_LIBRARIES})
  target_compile_definitions(wxWidgets::wxWidgets INTERFACE ${wxWidgets_DEFINITIONS} ${wxWidgets_DEFINITIONS_DEBUG})
endif()

I would love to remove this hack.

Be-ing commented 2 years ago

The same mixup of release and debug libraries is happening with expat :tired_face:

dg0yt commented 2 years ago

The same mixup of release and debug libraries is happening with expat

There is a number of ports without sufficient wrappers. I fixed zlib recently, libjepg-turbo is waiting for merge (#19319, a hard fight for a straightforward wrapper), and png might be the next one. Basic rule: check, fix, submit.

Be-ing commented 2 years ago

I've tried looking for documentation how these vcpkg-cmake-wrapper.cmake files work but have not found it. From digging into the source code of the vcpkg toolchain file, it seems they get called when an application calls find_package? I don't really understand how to use those to fix this problem with expat.

dg0yt commented 2 years ago

@Be-ing Getting off-topic, but yes, that is how I found what to do. Summary:

For expat, there already is a vcpkg_cmake_wrapper.cmake but it probably needs a modification due to an undocumented behaviour of CMake's select_library_configurations (cf. https://gitlab.kitware.com/cmake/cmake/-/issues/22509).

And of course maintaining a wrapper needs awareness of different names depending on triplet...

Be-ing commented 2 years ago

It turns out the expat port is okay and already has a working wrapper. I wasn't using it because I wrote my own Findexpat.cmake module because I didn't realize there was already a FindEXPAT.cmake (capitals) module included in CMake which the wrapper is designed for.

playgithub commented 2 years ago

@Be-ing So it is blocking. If there is only a dependency graph, writing a cmake file with ExternalProject_Add / FetchContent to install the dependencies is much easier than debugging the bugs in the case.

Be-ing commented 2 years ago

I don't understand what that comment had anything to do with the discussion here.

playgithub commented 2 years ago

I don't understand what that comment had anything to do with the discussion here.

As you can see, the issue has not been solved for 3 months, so I'm trying to see if there is a better way globally. After trying different C++ package managers, I think Linux's native package manager is the best, default in

When a special build of a lib is in need, it can be installed manually in

I don't know if a package in vcpkg can be overridden by a manually installed lib.

Be-ing commented 2 years ago

Discussing other package managers is off topic. I'm not interested in investing weeks of work switching. If you're only writing software for Linux then there is no need for vcpkg nor wxWidgets.

HWiman-ICONIC commented 2 years ago

I have had the same problem for quite some time, i.e. release wxWidgets libraries are linked instead of debug libraries in x64-Debug mode. It has worked correctly earlier. I backtracked the last port file that worked and (manually) merged it to current master. Indeed, I think attached port file fixes the problem. I do not if it breaks builds on Linux, but hopefully it is a help.

Please, if you find the fix correct, can someone make a PR and make sure it gets included? I tend to mess things up when trying.. fix-debug-libs.patch.txt portfile.cmake.txt ..

copymark commented 2 years ago

@HWiman-ICONIC

Don't know if that is the best solution, but it fixes the issue. Thank you

playgithub commented 2 years ago

@HWiman-ICONIC @copymark

In fix-debug-libs.patch.txt,

file(RENAME ${CURRENT_PACKAGES_DIR}/debug/lib/mswud ${CURRENT_PACKAGES_DIR}/lib/mswud)

Moving mswud to a folder for release is not so good

playgithub commented 2 years ago

Will the workaround below for FindwxWidgets to work properly?

EternalSaga commented 2 years ago

The same errror when I was using visual studio 2022. The debug version try to link the release version wxwidgets and the debug version app cannot find the release dll when I was debugging.

JackBoosY commented 2 years ago

@EternalSaga Try #17111.