microsoft / vcpkg

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

[libdatachannel] build failure #39812

Closed agnickolov closed 2 weeks ago

agnickolov commented 1 month ago

Operating system

Windows

Compiler

MSVC

Steps to reproduce the behavior

Build a project using static CRT linkage (VCPKG_TARGET_TRIPLET=x64-windows-static) that depends on libdatachannel. The project generates fine. However, trying to link an executable within the generated workspace fails with errors within libdatachannel. It is configured to use the DLL version of its dependency libjuice, but vcpkg builds the static version of that library as instructed.

Failure logs

4>datachannel-static.lib(icetransport.cpp.obj) : error LNK2019: unresolved external symbol __imp_juice_create referenced in function "public: __cdecl rtc::impl::IceTransport::IceTransport(struct rtc::Configuration const &,class std::function<void __cdecl(class rtc::Candidate const &)>,class std::function<void __cdecl(enum rtc::impl::Transport::State)>,class std::function<void __cdecl(enum rtc::impl::IceTransport::GatheringState)>)" (??0IceTransport@impl@rtc@@QEAA@AEBUConfiguration@2@V?$function@$$A6AXAEBVCandidate@rtc@@@Z@std@@V?$function@$$A6AXW4State@Transport@impl@rtc@@@Z@5@V?$function@$$A6AXW4GatheringState@IceTransport@impl@rtc@@@Z@5@@Z)
4>datachannel-static.lib(icetransport.cpp.obj) : error LNK2019: unresolved external symbol __imp_juice_destroy referenced in function "public: __cdecl rtc::impl::IceTransport::IceTransport(struct rtc::Configuration const &,class std::function<void __cdecl(class rtc::Candidate const &)>,class std::function<void __cdecl(enum rtc::impl::Transport::State)>,class std::function<void __cdecl(enum rtc::impl::IceTransport::GatheringState)>)" (??0IceTransport@impl@rtc@@QEAA@AEBUConfiguration@2@V?$function@$$A6AXAEBVCandidate@rtc@@@Z@std@@V?$function@$$A6AXW4State@Transport@impl@rtc@@@Z@5@V?$function@$$A6AXW4GatheringState@IceTransport@impl@rtc@@@Z@5@@Z)
4>datachannel-static.lib(icetransport.cpp.obj) : error LNK2019: unresolved external symbol __imp_juice_gather_candidates referenced in function "public: void __cdecl rtc::impl::IceTransport::gatherLocalCandidates(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class std::vector<struct rtc::IceServer,class std::allocator<struct rtc::IceServer> >)" (?gatherLocalCandidates@IceTransport@impl@rtc@@QEAAXV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V?$vector@UIceServer@rtc@@V?$allocator@UIceServer@rtc@@@std@@@5@@Z)
4>datachannel-static.lib(icetransport.cpp.obj) : error LNK2019: unresolved external symbol __imp_juice_get_local_description referenced in function "public: class rtc::Description __cdecl rtc::impl::IceTransport::getLocalDescription(enum rtc::Description::Type)const " (?getLocalDescription@IceTransport@impl@rtc@@QEBA?AVDescription@3@W4Type@43@@Z)
4>datachannel-static.lib(icetransport.cpp.obj) : error LNK2019: unresolved external symbol __imp_juice_set_remote_description referenced in function "public: void __cdecl rtc::impl::IceTransport::setRemoteDescription(class rtc::Description const &)" (?setRemoteDescription@IceTransport@impl@rtc@@QEAAXAEBVDescription@3@@Z)
4>datachannel-static.lib(icetransport.cpp.obj) : error LNK2019: unresolved external symbol __imp_juice_add_remote_candidate referenced in function "public: bool __cdecl rtc::impl::IceTransport::addRemoteCandidate(class rtc::Candidate const &)" (?addRemoteCandidate@IceTransport@impl@rtc@@QEAA_NAEBVCandidate@3@@Z)
4>datachannel-static.lib(icetransport.cpp.obj) : error LNK2019: unresolved external symbol __imp_juice_add_turn_server referenced in function "private: void __cdecl rtc::impl::IceTransport::addIceServer(struct rtc::IceServer)" (?addIceServer@IceTransport@impl@rtc@@AEAAXUIceServer@3@@Z)
4>datachannel-static.lib(icetransport.cpp.obj) : error LNK2019: unresolved external symbol __imp_juice_send_diffserv referenced in function "private: virtual bool __cdecl rtc::impl::IceTransport::outgoing(class std::shared_ptr<struct rtc::Message>)" (?outgoing@IceTransport@impl@rtc@@EEAA_NV?$shared_ptr@UMessage@rtc@@@std@@@Z)
4>datachannel-static.lib(icetransport.cpp.obj) : error LNK2019: unresolved external symbol __imp_juice_get_selected_candidates referenced in function "public: bool __cdecl rtc::impl::IceTransport::getSelectedCandidatePair(class rtc::Candidate *,class rtc::Candidate *)" (?getSelectedCandidatePair@IceTransport@impl@rtc@@QEAA_NPEAVCandidate@3@0@Z)
4>datachannel-static.lib(icetransport.cpp.obj) : error LNK2019: unresolved external symbol __imp_juice_get_selected_addresses referenced in function "public: class std::optional<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > __cdecl rtc::impl::IceTransport::getLocalAddress(void)const " (?getLocalAddress@IceTransport@impl@rtc@@QEBA?AV?$optional@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@std@@XZ)
4>datachannel-static.lib(icetransport.cpp.obj) : error LNK2019: unresolved external symbol __imp_juice_set_log_level referenced in function "public: __cdecl rtc::impl::IceTransport::IceTransport(struct rtc::Configuration const &,class std::function<void __cdecl(class rtc::Candidate const &)>,class std::function<void __cdecl(enum rtc::impl::Transport::State)>,class std::function<void __cdecl(enum rtc::impl::IceTransport::GatheringState)>)" (??0IceTransport@impl@rtc@@QEAA@AEBUConfiguration@2@V?$function@$$A6AXAEBVCandidate@rtc@@@Z@std@@V?$function@$$A6AXW4State@Transport@impl@rtc@@@Z@5@V?$function@$$A6AXW4GatheringState@IceTransport@impl@rtc@@@Z@5@@Z)
4>datachannel-static.lib(icetransport.cpp.obj) : error LNK2019: unresolved external symbol __imp_juice_set_log_handler referenced in function "public: __cdecl rtc::impl::IceTransport::IceTransport(struct rtc::Configuration const &,class std::function<void __cdecl(class rtc::Candidate const &)>,class std::function<void __cdecl(enum rtc::impl::Transport::State)>,class std::function<void __cdecl(enum rtc::impl::IceTransport::GatheringState)>)" (??0IceTransport@impl@rtc@@QEAA@AEBUConfiguration@2@V?$function@$$A6AXAEBVCandidate@rtc@@@Z@std@@V?$function@$$A6AXW4State@Transport@impl@rtc@@@Z@5@V?$function@$$A6AXW4GatheringState@IceTransport@impl@rtc@@@Z@5@@Z)

Additional context

The problem lies within the following construct within libdatachannel's CMakeLists.txt (lines 418-430):

    if(USE_SYSTEM_JUICE)
        find_package(LibJuice REQUIRED)
        target_compile_definitions(datachannel PRIVATE RTC_SYSTEM_JUICE=1)
        target_compile_definitions(datachannel-static PRIVATE RTC_SYSTEM_JUICE=1)
        target_link_libraries(datachannel PRIVATE LibJuice::LibJuice)
        target_link_libraries(datachannel-static PRIVATE LibJuice::LibJuice)
    else()
        add_subdirectory(deps/libjuice EXCLUDE_FROM_ALL)
        target_compile_definitions(datachannel PRIVATE RTC_SYSTEM_JUICE=0)
        target_compile_definitions(datachannel-static PRIVATE RTC_SYSTEM_JUICE=0)
        target_link_libraries(datachannel PRIVATE LibJuice::LibJuiceStatic)
        target_link_libraries(datachannel-static PRIVATE LibJuice::LibJuiceStatic)
    endif()

vcpkg uses the system version of the above code due to -DPREFER_SYSTEM_LIB=ON in the portfile. However, the above code instructs the generator to always use a libjuice shared library as a dependency of libdatachannel. According to the author this is actually intended. However, in the build model within the vcpkg port the external library flavor depends on the linkage for the project. Therefore the above should be modified with a patch within the port to discriminate the dependency:

    if(USE_SYSTEM_JUICE)
        find_package(LibJuice REQUIRED)
        target_compile_definitions(datachannel PRIVATE RTC_SYSTEM_JUICE=1)
        target_compile_definitions(datachannel-static PRIVATE RTC_SYSTEM_JUICE=1)
        target_link_libraries(datachannel PRIVATE LibJuice::LibJuice)
        target_link_libraries(datachannel-static PRIVATE LibJuice::LibJuiceStatic)
    else()
        add_subdirectory(deps/libjuice EXCLUDE_FROM_ALL)
        target_compile_definitions(datachannel PRIVATE RTC_SYSTEM_JUICE=0)
        target_compile_definitions(datachannel-static PRIVATE RTC_SYSTEM_JUICE=0)
        target_link_libraries(datachannel PRIVATE LibJuice::LibJuiceStatic)
        target_link_libraries(datachannel-static PRIVATE LibJuice::LibJuiceStatic)
    endif()

The else clause is irrelevant and doesn't need to be patched. Only the last line in the if clause above needs to be patched.

dg0yt commented 1 month ago

You are suggesting

-       target_link_libraries(datachannel-static PRIVATE LibJuice::LibJuice)
+       target_link_libraries(datachannel-static PRIVATE LibJuice::LibJuiceStatic)

but even the static triplets build provide LibJuice::LibJuice.

If I look into the installed juice.h, I would guess that the problem is that it would need a JUICE_STATIC definition for static usage, or a simple fixup in the portfile which removes the need for the definition.

agnickolov commented 1 month ago

I suggested what seemed like the most simple and logical change to make. Presumably LibJuiceStatic provides the right definitions for its dependents. If it doesn't then that's a problem within libjuice, not libdatachannel. I'm not opposed to a different solution as long as my project builds and works, however.

agnickolov commented 3 weeks ago

Any update here? Nothing seems to have been fixed one way or another...

MonicaLiu0311 commented 3 weeks ago

@dg0yt Please help take a look at #40328 to see if there is a better solution. Thanks🌼

dg0yt commented 3 weeks ago

Thanks @MonicaLiu0311. The idea was a little different. I will take a look.

dg0yt commented 3 weeks ago

My proposal: #40335. Which really removes the needed for using JUICE_STATIC downstream.

dg0yt commented 3 weeks ago

And #40337 provides a similar update+cleanup+fixup to libdatachannel.