debug/AssertFatal.cpp Not Included in yogacore Build with file(GLOB), Causes Linker Error When Building Yoga 3.2.1 as Shared Library (yoga/CMakeLists.txt Fix) #1806

Open
opened 2025-04-03 05:44:52 -07:00 by natalia-hultrix · 0 comments
natalia-hultrix commented 2025-04-03 05:44:52 -07:00 (Migrated from github.com)

Description

Summary

When building the yogacore library with the default CMakeLists.txt in the yoga/ directory, the debug/AssertFatal.cpp file (which defines facebook::yoga::fatalWithMessage) is not included in the source list when using file(GLOB ...). This doesn’t affect the static build (libyogacore.a) in my current test suite, but it causes a linker error (undefined reference to facebook::yoga::fatalWithMessage) when building as a shared library (libyogacore.so).

Steps to Reproduce

  1. Modify yoga/CMakeLists.txt to support shared libraries:
    option(BUILD_SHARED_LIBS "Build yogacore as a shared library" OFF)
    if(BUILD_SHARED_LIBS)
        add_library(yogacore SHARED ${SOURCES})
    else()
        add_library(yogacore STATIC ${SOURCES})
    endif()
    
  2. Run CMake with shared library enabled:
    cmake -B build -S . -DBUILD_SHARED_LIBS=ON
    make -j$(nproc)
    
  3. Observe the linker error during the yogatests build:
    /usr/bin/ld: CMakeFiles/yogatests.dir/StyleTest.cpp.o: in function `facebook::yoga::Style::computeMargin(...)`:
    StyleTest.cpp:(.text...): undefined reference to `facebook::yoga::fatalWithMessage(char const*)`
    

Expected Behavior

  • The yogacore library (static or shared) should include all necessary source files, including debug/AssertFatal.cpp, so that fatalWithMessage is defined and the build completes successfully.

Actual Behavior

  • The original file(GLOB SOURCES CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp ${CMAKE_CURRENT_SOURCE_DIR}/**/*.cpp) does not include debug/AssertFatal.cpp.
  • Static builds succeed due to linker laziness (if fatalWithMessage isn’t called), but shared builds fail with an undefined reference error because the symbol is referenced in StyleTest.cpp (via Style.h).

Root Cause

  • The file(GLOB ...) pattern in yoga/CMakeLists.txt fails to recurse into the debug/ subdirectory, omitting debug/AssertFatal.cpp. This is unexpected since /**/*.cpp should include subdirectories, but it doesn’t work as intended in my environment (CMake 3.26, Fedora).

My Fix

I modified yoga/CMakeLists.txt to use file(GLOB_RECURSE ...) instead:

file(GLOB_RECURSE SOURCES CONFIGURE_DEPENDS
    ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)

This correctly includes debug/AssertFatal.cpp, and both static and shared builds succeed:

cmake -B build -S . -DBUILD_SHARED_LIBS=ON  # Works
cmake -B build -S . -DBUILD_SHARED_LIBS=OFF # Works
make -j$(nproc)

Suggested Action

  • Update yoga/CMakeLists.txt to use file(GLOB_RECURSE ...) or explicitly include debug/AssertFatal.cpp to ensure all necessary sources are built into yogacore.
  • Alternatively, clarify in the documentation if debug/AssertFatal.cpp is intentionally excluded and how users should handle shared library builds.

Environment

  • OS: Fedora 41
  • CMake Version: 3.26
  • Compiler: GCC
  • Yoga Version: 3.2.1

Additional Notes

  • The static build’s success seems to rely on the linker not needing fatalWithMessage in my test suite. If tests or consumers call it (e.g., via Style.h), the static build could fail too.
  • Full modified CMakeLists.txt:
    cmake_minimum_required(VERSION 3.13...3.26)
    project(yogacore)
    set(CMAKE_VERBOSE_MAKEFILE on)
    
    if(TARGET yogacore)
        return()
    endif()
    
    include(CheckIPOSupported)
    
    option(BUILD_SHARED_LIBS "Build yogacore as a shared library" OFF)
    
    set(YOGA_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/..)
    include(${YOGA_ROOT}/cmake/project-defaults.cmake)
    
    file(GLOB_RECURSE SOURCES CONFIGURE_DEPENDS
        ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
    
    if(BUILD_SHARED_LIBS)
        add_library(yogacore SHARED ${SOURCES})
    else()
        add_library(yogacore STATIC ${SOURCES})
    endif()
    
    if(ANDROID)
        target_link_libraries(yogacore log)
    endif()
    
    check_ipo_supported(RESULT result)
    if(result)
        set_target_properties(yogacore PROPERTIES
            CMAKE_INTERPROCEDURAL_OPTIMIZATION true)
    endif()
    
    target_include_directories(yogacore
        PUBLIC
        $<BUILD_INTERFACE:${YOGA_ROOT}>
        $<INSTALL_INTERFACE:${CMAKE_INSTALL_PREFIX}/include/yoga>)
    
### Description #### Summary When building the `yogacore` library with the default `CMakeLists.txt` in the `yoga/` directory, the `debug/AssertFatal.cpp` file (which defines `facebook::yoga::fatalWithMessage`) is not included in the source list when using `file(GLOB ...)`. This doesn’t affect the static build (`libyogacore.a`) in my current test suite, but it causes a linker error (`undefined reference to facebook::yoga::fatalWithMessage`) when building as a shared library (`libyogacore.so`). #### Steps to Reproduce 1. Modify `yoga/CMakeLists.txt` to support shared libraries: ```cmake option(BUILD_SHARED_LIBS "Build yogacore as a shared library" OFF) if(BUILD_SHARED_LIBS) add_library(yogacore SHARED ${SOURCES}) else() add_library(yogacore STATIC ${SOURCES}) endif() ``` 3. Run CMake with shared library enabled: ```bash cmake -B build -S . -DBUILD_SHARED_LIBS=ON make -j$(nproc) ``` 4. Observe the linker error during the `yogatests` build: ``` /usr/bin/ld: CMakeFiles/yogatests.dir/StyleTest.cpp.o: in function `facebook::yoga::Style::computeMargin(...)`: StyleTest.cpp:(.text...): undefined reference to `facebook::yoga::fatalWithMessage(char const*)` ``` #### Expected Behavior - The `yogacore` library (static or shared) should include all necessary source files, including `debug/AssertFatal.cpp`, so that `fatalWithMessage` is defined and the build completes successfully. #### Actual Behavior - The original `file(GLOB SOURCES CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp ${CMAKE_CURRENT_SOURCE_DIR}/**/*.cpp)` does not include `debug/AssertFatal.cpp`. - Static builds succeed due to linker laziness (if `fatalWithMessage` isn’t called), but shared builds fail with an `undefined reference` error because the symbol is referenced in `StyleTest.cpp` (via `Style.h`). #### Root Cause - The `file(GLOB ...)` pattern in `yoga/CMakeLists.txt` fails to recurse into the `debug/` subdirectory, omitting `debug/AssertFatal.cpp`. This is unexpected since `/**/*.cpp` should include subdirectories, but it doesn’t work as intended in my environment (CMake 3.26, Fedora). #### My Fix I modified `yoga/CMakeLists.txt` to use `file(GLOB_RECURSE ...)` instead: ```cmake file(GLOB_RECURSE SOURCES CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) ``` This correctly includes `debug/AssertFatal.cpp`, and both static and shared builds succeed: ```bash cmake -B build -S . -DBUILD_SHARED_LIBS=ON # Works cmake -B build -S . -DBUILD_SHARED_LIBS=OFF # Works make -j$(nproc) ``` #### Suggested Action - Update `yoga/CMakeLists.txt` to use `file(GLOB_RECURSE ...)` or explicitly include `debug/AssertFatal.cpp` to ensure all necessary sources are built into `yogacore`. - Alternatively, clarify in the documentation if `debug/AssertFatal.cpp` is intentionally excluded and how users should handle shared library builds. #### Environment - OS: Fedora 41 - CMake Version: 3.26 - Compiler: GCC - Yoga Version: 3.2.1 #### Additional Notes - The static build’s success seems to rely on the linker not needing `fatalWithMessage` in my test suite. If tests or consumers call it (e.g., via `Style.h`), the static build could fail too. - Full modified `CMakeLists.txt`: ```cmake cmake_minimum_required(VERSION 3.13...3.26) project(yogacore) set(CMAKE_VERBOSE_MAKEFILE on) if(TARGET yogacore) return() endif() include(CheckIPOSupported) option(BUILD_SHARED_LIBS "Build yogacore as a shared library" OFF) set(YOGA_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/..) include(${YOGA_ROOT}/cmake/project-defaults.cmake) file(GLOB_RECURSE SOURCES CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) if(BUILD_SHARED_LIBS) add_library(yogacore SHARED ${SOURCES}) else() add_library(yogacore STATIC ${SOURCES}) endif() if(ANDROID) target_link_libraries(yogacore log) endif() check_ipo_supported(RESULT result) if(result) set_target_properties(yogacore PROPERTIES CMAKE_INTERPROCEDURAL_OPTIMIZATION true) endif() target_include_directories(yogacore PUBLIC $<BUILD_INTERFACE:${YOGA_ROOT}> $<INSTALL_INTERFACE:${CMAKE_INSTALL_PREFIX}/include/yoga>) ```
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: DaddyFrosty/yoga#1806
No description provided.