Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@ cmake_minimum_required(VERSION 3.16)
project(one VERSION 6.1.0 LANGUAGES C CXX)
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")

include(DebugSymbols)
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
Comment thread
jviotti marked this conversation as resolved.
set(ONE_DEBUG_SYMBOLS_DEFAULT OFF)
else()
set(ONE_DEBUG_SYMBOLS_DEFAULT ON)
endif()
option(ONE_DEBUG_SYMBOLS "Compile and extract debug symbols" ${ONE_DEBUG_SYMBOLS_DEFAULT})
if(ONE_DEBUG_SYMBOLS)
sourcemeta_debug_symbols_enable()
endif()

# Options
option(ONE_TESTS "Build the One unit tests" ON)
option(ONE_SERVER "Build the One server" ON)
Expand Down Expand Up @@ -86,10 +97,19 @@ if(ONE_INDEX)
if(ONE_ENTERPRISE)
add_subdirectory(enterprise/index)
endif()

if(ONE_DEBUG_SYMBOLS)
sourcemeta_debug_symbols_extract(sourcemeta_one_index
COMPONENT sourcemeta_one)
endif()
endif()

if(ONE_SERVER)
add_subdirectory(src/server)
if(ONE_DEBUG_SYMBOLS)
sourcemeta_debug_symbols_extract(sourcemeta_one_server
COMPONENT sourcemeta_one)
endif()
endif()

sourcemeta_target_clang_format(SOURCES
Expand Down
7 changes: 6 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ RUN cmake -S /source -B ./build -G Ninja \
-DONE_SERVER:BOOL=ON \
-DONE_TESTS:BOOL=ON \
-DONE_ENTERPRISE:BOOL=OFF \
-DBUILD_SHARED_LIBS:BOOL=OFF
-DBUILD_SHARED_LIBS:BOOL=OFF \
-DONE_DEBUG_SYMBOLS:BOOL=ON

RUN cmake --build /build \
--config ${SOURCEMETA_ONE_BUILD_TYPE} \
Expand Down Expand Up @@ -62,8 +63,12 @@ LABEL org.opencontainers.image.authors="Sourcemeta <hello@sourcemeta.com>"

COPY --from=builder /usr/bin/sourcemeta-one-index \
/usr/bin/sourcemeta-one-index
COPY --from=builder /usr/bin/sourcemeta-one-index.debug \
/usr/bin/sourcemeta-one-index.debug
COPY --from=builder /usr/bin/sourcemeta-one-server \
/usr/bin/sourcemeta-one-server
COPY --from=builder /usr/bin/sourcemeta-one-server.debug \
/usr/bin/sourcemeta-one-server.debug
COPY --from=builder /usr/share/sourcemeta/one \
/usr/share/sourcemeta/one

Expand Down
74 changes: 74 additions & 0 deletions cmake/DebugSymbols.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
macro(sourcemeta_debug_symbols_enable)
message(STATUS "Enabling debug symbols globally")
add_compile_options(-g)
Comment thread
jviotti marked this conversation as resolved.
# GCC's `-Wmaybe-uninitialized` produces false positives in
# template code (`std::tuple`, `std::optional`) when `-g`
# changes inlining decisions under `-O3 -flto`
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
add_compile_options(-Wno-error=maybe-uninitialized)
endif()
endmacro()

function(sourcemeta_debug_symbols_extract TARGET_NAME)
cmake_parse_arguments(EXTRACT_DEBUG_SYMBOLS "" "COMPONENT" "" ${ARGN})
if(NOT EXTRACT_DEBUG_SYMBOLS_COMPONENT)
message(FATAL_ERROR "The COMPONENT argument is required")
endif()

set(BINARY_INPUT "$<TARGET_FILE:${TARGET_NAME}>")
get_target_property(BINARY_OUTPUT_NAME "${TARGET_NAME}" OUTPUT_NAME)
if(NOT BINARY_OUTPUT_NAME)
set(BINARY_OUTPUT_NAME "${TARGET_NAME}")
endif()
get_target_property(BINARY_OUTPUT_DIR "${TARGET_NAME}" RUNTIME_OUTPUT_DIRECTORY)
if(NOT BINARY_OUTPUT_DIR)
get_target_property(BINARY_OUTPUT_DIR "${TARGET_NAME}" BINARY_DIR)
endif()
get_target_property(BINARY_OUTPUT_SUFFIX "${TARGET_NAME}" SUFFIX)
if(NOT BINARY_OUTPUT_SUFFIX)
set(BINARY_OUTPUT_SUFFIX "${CMAKE_EXECUTABLE_SUFFIX}")
endif()
set(BINARY_PATH "${BINARY_OUTPUT_DIR}/${BINARY_OUTPUT_NAME}${BINARY_OUTPUT_SUFFIX}")

if(APPLE)
message(STATUS "Extracting debug symbols (.dSYM) for: ${TARGET_NAME}")
# With `-flto=full`, the post-LTO object normally lives in
# `/tmp/lto.o` and is removed immediately after the link, which
# makes `dsymutil` silently produce a near-empty bundle. Pin
# the LTO temp under the binary's build dir so it persists long
# enough for `dsymutil` to consume it
target_link_options("${TARGET_NAME}" PRIVATE
"LINKER:-object_path_lto,${BINARY_INPUT}.lto.o")

find_program(DSYMUTIL_EXECUTABLE dsymutil REQUIRED)
add_custom_command(OUTPUT "${BINARY_PATH}.dSYM"
COMMAND "${DSYMUTIL_EXECUTABLE}" "${BINARY_INPUT}"
-o "${BINARY_PATH}.dSYM"
DEPENDS "${TARGET_NAME}"
VERBATIM)
add_custom_target("${TARGET_NAME}_debug_symbols" ALL
DEPENDS "${BINARY_PATH}.dSYM")

install(DIRECTORY "${BINARY_PATH}.dSYM"
DESTINATION "${CMAKE_INSTALL_BINDIR}"
COMPONENT "${EXTRACT_DEBUG_SYMBOLS_COMPONENT}")
elseif(UNIX)
message(STATUS "Extracting debug symbols (.debug) for: ${TARGET_NAME}")
add_custom_command(OUTPUT "${BINARY_PATH}.debug"
COMMAND "${CMAKE_OBJCOPY}" --only-keep-debug
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: CMAKE_OBJCOPY used without existence check. Missing tool will break the debug-symbol target at build time. Add a required tool check before creating commands.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At cmake/DebugSymbols.cmake, line 47:

<comment>`CMAKE_OBJCOPY` used without existence check. Missing tool will break the debug-symbol target at build time. Add a required tool check before creating commands.</comment>

<file context>
@@ -0,0 +1,61 @@
+      COMPONENT "${EXTRACT_DEBUG_SYMBOLS_COMPONENT}")
+  elseif(UNIX)
+    add_custom_command(OUTPUT "${BINARY_PATH}.debug"
+      COMMAND "${CMAKE_OBJCOPY}" --only-keep-debug
+              "${BINARY_PATH}" "${BINARY_PATH}.debug"
+      COMMAND "${CMAKE_OBJCOPY}" --strip-debug "${BINARY_PATH}"
</file context>

"${BINARY_INPUT}" "${BINARY_PATH}.debug"
COMMAND "${CMAKE_OBJCOPY}" --strip-debug "${BINARY_INPUT}"
COMMAND "${CMAKE_OBJCOPY}"
"--add-gnu-debuglink=${BINARY_PATH}.debug" "${BINARY_INPUT}"
DEPENDS "${TARGET_NAME}"
VERBATIM)
add_custom_target("${TARGET_NAME}_debug_symbols" ALL
DEPENDS "${BINARY_PATH}.debug")

install(FILES "${BINARY_PATH}.debug"
DESTINATION "${CMAKE_INSTALL_BINDIR}"
COMPONENT "${EXTRACT_DEBUG_SYMBOLS_COMPONENT}")
else()
message(FATAL_ERROR "Unsupported platform: ${CMAKE_SYSTEM_NAME}")
endif()
endfunction()
7 changes: 6 additions & 1 deletion enterprise/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ RUN cmake -S /source -B ./build -G Ninja \
-DONE_SERVER:BOOL=ON \
-DONE_TESTS:BOOL=ON \
-DONE_ENTERPRISE:BOOL=ON \
-DBUILD_SHARED_LIBS:BOOL=OFF
-DBUILD_SHARED_LIBS:BOOL=OFF \
-DONE_DEBUG_SYMBOLS:BOOL=ON

RUN cmake --build /build \
--config ${SOURCEMETA_ONE_BUILD_TYPE} \
Expand Down Expand Up @@ -94,8 +95,12 @@ LABEL org.opencontainers.image.authors="Sourcemeta <hello@sourcemeta.com>"

COPY --from=builder /usr/bin/sourcemeta-one-index \
/usr/bin/sourcemeta-one-index
COPY --from=builder /usr/bin/sourcemeta-one-index.debug \
/usr/bin/sourcemeta-one-index.debug
COPY --from=builder /usr/bin/sourcemeta-one-server \
/usr/bin/sourcemeta-one-server
COPY --from=builder /usr/bin/sourcemeta-one-server.debug \
/usr/bin/sourcemeta-one-server.debug
COPY --from=builder /usr/share/sourcemeta/one \
/usr/share/sourcemeta/one

Expand Down
5 changes: 5 additions & 0 deletions test/cli/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ if(ONE_INDEX)
sourcemeta_one_test_cli(common index fail-invalid-schema-uri-percentage)
sourcemeta_one_test_cli(common index fail-invalid-schema-yaml)
sourcemeta_one_test_cli(common index fail-maximum-entries-non-numeric-value)
sourcemeta_one_test_cli(common index debug-symbols)
sourcemeta_one_test_cli(common index help)
sourcemeta_one_test_cli(common index help-skip-banner)
sourcemeta_one_test_cli(common index no-arguments)
Expand Down Expand Up @@ -149,3 +150,7 @@ if(ONE_INDEX)
sourcemeta_one_test_cli(community index fail-lint-rule-enterprise-only)
endif()
endif()

if(ONE_SERVER)
sourcemeta_one_test_cli(common server debug-symbols)
endif()
44 changes: 44 additions & 0 deletions test/cli/index/common/debug-symbols.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#!/bin/sh

set -o errexit
set -o nounset

BINARY="$1"

TMP="$(mktemp -d)"
Comment thread
jviotti marked this conversation as resolved.
clean() { rm -rf "$TMP"; }
trap clean EXIT

if [ "$(uname -s)" = "Darwin" ]; then
# `_main` is the Mach-O mangled name of `main`. We resolve its
# address, then ask `atos` to symbolicate. `atos` follows the
# binary's debug map (which can point at a `.dSYM` bundle via
# UUID through Spotlight, at the original `.o` files, or both)
# so the test does not depend on where the symbols ended up.
# When DWARF is reachable the output ends with `(file:line)`;
# without DWARF it ends with `+ <offset>`
ADDRESS="$(nm "$BINARY" | awk '$3 == "_main" {print "0x"$1; exit}')"
test -n "$ADDRESS" || { echo "no main symbol in $BINARY" >&2; exit 1; }
atos -o "$BINARY" "$ADDRESS" > "$TMP/output.txt"
grep -qE '\(.+:[0-9]+\)' "$TMP/output.txt" || {
echo "no source location resolved:" >&2
cat "$TMP/output.txt" >&2
exit 1
}
else
# `nm --line-numbers` annotates each symbol with `<file>:<line>`
# when source mapping is available. It uses BFD, which follows
# the binary's `.gnu_debuglink` section to locate a `.debug`
# sidecar in any standard location, so the test does not depend
# on where the sidecar ended up. We do not pin to a single symbol
# because LTO routinely splits or stubs out specific symbols
# (notably `main`), losing their line mapping while leaving the
# rest of the binary fully annotated. As long as some symbol
# resolves, the sidecar is reachable and DWARF is intact
nm --line-numbers "$BINARY" > "$TMP/output.txt"
grep -qE ':[1-9][0-9]*$' "$TMP/output.txt" || {
echo "no symbol resolved to a source location" >&2
head -5 "$TMP/output.txt" >&2
exit 1
}
fi
44 changes: 44 additions & 0 deletions test/cli/server/common/debug-symbols.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#!/bin/sh

set -o errexit
set -o nounset

BINARY="$1"

TMP="$(mktemp -d)"
clean() { rm -rf "$TMP"; }
trap clean EXIT

if [ "$(uname -s)" = "Darwin" ]; then
# `_main` is the Mach-O mangled name of `main`. We resolve its
# address, then ask `atos` to symbolicate. `atos` follows the
# binary's debug map (which can point at a `.dSYM` bundle via
# UUID through Spotlight, at the original `.o` files, or both)
# so the test does not depend on where the symbols ended up.
# When DWARF is reachable the output ends with `(file:line)`;
# without DWARF it ends with `+ <offset>`
ADDRESS="$(nm "$BINARY" | awk '$3 == "_main" {print "0x"$1; exit}')"
test -n "$ADDRESS" || { echo "no main symbol in $BINARY" >&2; exit 1; }
atos -o "$BINARY" "$ADDRESS" > "$TMP/output.txt"
grep -qE '\(.+:[0-9]+\)' "$TMP/output.txt" || {
echo "no source location resolved:" >&2
cat "$TMP/output.txt" >&2
exit 1
}
else
# `nm --line-numbers` annotates each symbol with `<file>:<line>`
# when source mapping is available. It uses BFD, which follows
# the binary's `.gnu_debuglink` section to locate a `.debug`
# sidecar in any standard location, so the test does not depend
# on where the sidecar ended up. We do not pin to a single symbol
# because LTO routinely splits or stubs out specific symbols
# (notably `main`), losing their line mapping while leaving the
# rest of the binary fully annotated. As long as some symbol
# resolves, the sidecar is reachable and DWARF is intact
nm --line-numbers "$BINARY" > "$TMP/output.txt"
grep -qE ':[1-9][0-9]*$' "$TMP/output.txt" || {
echo "no symbol resolved to a source location" >&2
head -5 "$TMP/output.txt" >&2
exit 1
}
fi
Loading