Skip to content

cutils being PRIVATE in CMakeLists.txt causes a failure to embed libqjs from another project #1343

@TaylorRichberger

Description

@TaylorRichberger

I've created this simple sample project.

Source files

CmakeLists.txt

cmake_minimum_required(VERSION 3.21)
cmake_policy(VERSION 3.21)

project(qjs_test LANGUAGES C)

add_executable(
    qjs_test
    main.c
)

find_package(qjs REQUIRED CONFIG NAMES qjs quickjs)
find_package(Threads REQUIRED)

target_link_libraries(qjs_test PUBLIC qjs Threads::Threads ${CMAKE_DL_LIBS})

main.c

#include <quickjs.h>

int main() {
  JSRuntime *runtime = JS_NewRuntime();
  JS_FreeRuntime(runtime);
  return 0;
}

Building

I've cloned the current master branch of quickjs-ng into ./quickjs, and tried to build (full log attached; it's fairly long and not all of it is relevant):

bash-3.2$ cmake -Bbuild/quickjs -S./quickjs "-DCMAKE_INSTALL_PREFIX=$PWD/install" "-DCMAKE_PREFIX_PATH=$PWD/install"
-- The C compiler identification is AppleClang 17.0.0.17000603
-- Detecting C compiler ABI info
...
-- Configuring done (1.4s)
-- Generating done (0.0s)
-- Build files have been written to: /private/var/folders/4p/s82tj31s75n_8rlzw_nvz4t40000gn/T/tmp.CXu7DV1T8f/build/quickjs

bash-3.2$ cmake --build build/quickjs
[  4%] Building C object CMakeFiles/cutils.dir/cutils.c.o
[  9%] Linking C static library libcutils.a
[  9%] Built target cutils
[ 14%] Building C object CMakeFiles/qjs.dir/dtoa.c.o
...
[100%] Linking C executable function_source
[100%] Built target function_source

bash-3.2$ cmake --install build/quickjs
-- Install configuration: "Release"
-- Installing: /private/var/folders/4p/s82tj31s75n_8rlzw_nvz4t40000gn/T/tmp.CXu7DV1T8f/install/include/quickjs.h
-- Installing: /private/var/folders/4p/s82tj31s75n_8rlzw_nvz4t40000gn/T/tmp.CXu7DV1T8f/install/bin/qjs
-- Installing: /private/var/folders/4p/s82tj31s75n_8rlzw_nvz4t40000gn/T/tmp.CXu7DV1T8f/install/bin/qjsc
-- Installing: /private/var/folders/4p/s82tj31s75n_8rlzw_nvz4t40000gn/T/tmp.CXu7DV1T8f/install/lib/libqjs.a
-- Installing: /private/var/folders/4p/s82tj31s75n_8rlzw_nvz4t40000gn/T/tmp.CXu7DV1T8f/install/lib/cmake/quickjs/qjsConfig.cmake
-- Installing: /private/var/folders/4p/s82tj31s75n_8rlzw_nvz4t40000gn/T/tmp.CXu7DV1T8f/install/lib/cmake/quickjs/qjsConfig-release.cmake
-- Installing: /private/var/folders/4p/s82tj31s75n_8rlzw_nvz4t40000gn/T/tmp.CXu7DV1T8f/install/share/doc/quickjs/LICENSE
-- Installing: /private/var/folders/4p/s82tj31s75n_8rlzw_nvz4t40000gn/T/tmp.CXu7DV1T8f/install/share/doc/quickjs/examples
-- Installing: /private/var/folders/4p/s82tj31s75n_8rlzw_nvz4t40000gn/T/tmp.CXu7DV1T8f/install/share/doc/quickjs/examples/test_point.js
-- Installing: /private/var/folders/4p/s82tj31s75n_8rlzw_nvz4t40000gn/T/tmp.CXu7DV1T8f/install/share/doc/quickjs/examples/hello.js
-- Installing: /private/var/folders/4p/s82tj31s75n_8rlzw_nvz4t40000gn/T/tmp.CXu7DV1T8f/install/share/doc/quickjs/examples/test_fib.js
-- Installing: /private/var/folders/4p/s82tj31s75n_8rlzw_nvz4t40000gn/T/tmp.CXu7DV1T8f/install/share/doc/quickjs/examples/meson.build
-- Installing: /private/var/folders/4p/s82tj31s75n_8rlzw_nvz4t40000gn/T/tmp.CXu7DV1T8f/install/share/doc/quickjs/examples/fib_module.js
-- Installing: /private/var/folders/4p/s82tj31s75n_8rlzw_nvz4t40000gn/T/tmp.CXu7DV1T8f/install/share/doc/quickjs/examples/point.c
-- Installing: /private/var/folders/4p/s82tj31s75n_8rlzw_nvz4t40000gn/T/tmp.CXu7DV1T8f/install/share/doc/quickjs/examples/fib.c
-- Installing: /private/var/folders/4p/s82tj31s75n_8rlzw_nvz4t40000gn/T/tmp.CXu7DV1T8f/install/share/doc/quickjs/examples/pi_bigint.js
-- Installing: /private/var/folders/4p/s82tj31s75n_8rlzw_nvz4t40000gn/T/tmp.CXu7DV1T8f/install/share/doc/quickjs/examples/hello_module.js

bash-3.2$ cmake -Bbuild/qjs_test -S. "-DCMAKE_INSTALL_PREFIX=$PWD/install" "-DCMAKE_PREFIX_PATH=$PWD/install"
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD - Success
-- Found Threads: TRUE
-- Configuring done (0.1s)
-- Generating done (0.0s)
-- Build files have been written to: /private/var/folders/4p/s82tj31s75n_8rlzw_nvz4t40000gn/T/tmp.CXu7DV1T8f/build/qjs_test

bash-3.2$ cmake --build build/qjs_test
[ 50%] Building C object CMakeFiles/qjs_test.dir/main.c.o
[100%] Linking C executable qjs_test
Undefined symbols for architecture arm64:
  "___dbuf_put_u16", referenced from:
      _lre_compile in libqjs.a[3](libregexp.c.o)
      _re_parse_alternative in libqjs.a[3](libregexp.c.o)
      _re_emit_range in libqjs.a[3](libregexp.c.o)
      _re_emit_range in libqjs.a[3](libregexp.c.o)
      _re_emit_range in libqjs.a[3](libregexp.c.o)
      _re_emit_range in libqjs.a[3](libregexp.c.o)
      _JS_WriteString in libqjs.a[5](quickjs.c.o)
...
      _JS_NewStringLen in libqjs.a[5](quickjs.c.o)
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[2]: *** [qjs_test] Error 1
make[1]: *** [CMakeFiles/qjs_test.dir/all] Error 2
make: *** [all] Error 2

bash-3.2$

It looks like this is because you build cutils into a private library and link it into the qjs executable, but the cutils lib is not built into libqjs nor is it installed and exposed in the qjs target. In my case, I can work around it by either explicitly linking in the cutils lib:

find_library(CUTILS cutils PATHS "${CMAKE_SOURCE_DIR}/build/quickjs" REQUIRED)
target_link_libraries(qjs_test PUBLIC qjs Threads::Threads ${CMAKE_DL_LIBS} ${CUTILS})

Or adding the cutils.c file to my own build:

add_executable(
    qjs_test
    main.c
    ./quickjs/cutils.c
)

Fix

Quickjs needs to either export cutils symbols somehow (either by exposing the cutils library or including the object in the qjs library), inline the functions (by moving the cutils.c definitions to cutils.h and making them all static inline), or do some platform-specific post-link symbol localization.

I think the most simple and obvious choice would be the inlining, if you want to avoid name collision. Exposing them would probably necessitate a mass-rename of most of cutils symbols, and post-link symbol localization is platform specific, toolchain specific, and I have no idea what all the necessary tools even are, personally.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions