libsdl-org / SDL_image

Image decoding for many popular formats for Simple Directmedia Layer.
zlib License
513 stars 174 forks source link

Statically linking an executable with JPEG XL enabled breaks the build at link time #444

Closed nightmareci closed 2 months ago

nightmareci commented 3 months ago

I'm working on a project where I want to CMake-consume (via FetchContent), build, and statically link all the dependencies (SDL, all the satellite libraries) for distributed release builds. Enabling JPEG XL breaks the build though, as it needs C++, and C++ doesn't get enabled properly in this setup, so the build output throws a bunch of C++ linking errors. For now, adding an enable_language(CXX) gets it working, but that doesn't really seem correct, I don't think a CMake project (mine) consuming another (SDL_image) should have to do that, if my project's code doesn't include any C++. So, somehow, C++ needs to get enabled so the final statically linked executable can get the C++ code linked in.

I've encountered this bug with both SDL2 and SDL3.

madebr commented 3 months ago

This is a CMake quirk you're encountering. We do enable_language(CXX) in our cmake script. This sets the LINKER_LANGUAGE property of the SDL_image targets to CXX.

For some reason CMake needs enable_language(CXX) at the same (or higher) level when using any target that uses c++. I cannot immediately find an issue at CMake's issue tracker.

This minimal CMake project reproduces your issue:

C executable using a C++ static library ```cmake cmake_minimum_required(VERSION 3.25) project(masterproject LANGUAGES C) file(WRITE subproject/CMakeLists.txt [=====[ cmake_minimum_required(VERSION 3.25) project(subproject LANGUAGES C CXX) file(WRITE lib.cpp [=[ #include extern "C" { int exists(const char *filename) { std::error_code ec; return std::filesystem::exists(filename, ec); } } ]=]) add_library(sublibrary STATIC lib.cpp) target_link_libraries(sublibrary stdc++fs) set_property(TARGET sublibrary PROPERTY CXX_STANDARD 17) ]=====]) file(WRITE main.c [=[ #include extern int exists(const char *filename); int main(int argc, char *argv[]) { if (argc < 2) { fprintf(stderr, "Need argument\n"); return 1; } printf("Exists: %d\n", exists(argv[1])); return 0; } ]=]) add_subdirectory(subproject) add_executable(main main.c) target_link_libraries(main PRIVATE sublibrary) # Uncomment the following line to fix the link error # enable_language(CXX) ```
madebr commented 2 months ago

I'm closing this issue. Let's hope a future CMake release fixes this.