Skip to content

Commit

Permalink
[libc] Simplify integration tests by eliminating the artificial sysroot.
Browse files Browse the repository at this point in the history
The test binaries are built like any other executable but with two
additional linker options -static and -nostdlib.

Reviewed By: jhuber6

Differential Revision: https://reviews.llvm.org/D145298
  • Loading branch information
Siva Chandra Reddy committed Mar 6, 2023
1 parent 1a6dfa2 commit a7d869a
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 64 deletions.
104 changes: 40 additions & 64 deletions libc/cmake/modules/LLVMLibCTestRules.cmake
Expand Up @@ -438,74 +438,54 @@ function(add_integration_test test_name)
get_fq_target_name(${test_name}.libc fq_libc_target_name)

get_fq_deps_list(fq_deps_list ${INTEGRATION_TEST_DEPENDS})
# All integration tests setup TLS area and the main thread's self object.
# So, we need to link in the threads implementation. Likewise, the startup
# code also has to run init_array callbacks which potentially register
# their own atexit callbacks. So, link in exit and atexit also with all
# integration tests.
list(
APPEND fq_deps_list
list(APPEND fq_deps_list
# All integration tests setup TLS area and the main thread's self object.
# So, we need to link in the threads implementation. Likewise, the startup
# code also has to run init_array callbacks which potentially register
# their own atexit callbacks. So, link in exit and atexit also with all
# integration tests.
libc.src.__support.threads.thread
libc.src.stdlib.atexit
libc.src.stdlib.exit
libc.src.unistd.environ
libc.test.IntegrationTest.test)
)
list(APPEND memory_functions
libc.src.string.bcmp
libc.src.string.bzero
libc.src.string.memcmp
libc.src.string.memcpy
libc.src.string.memmove
libc.src.string.memset
)
# We remove the memory function deps because we want to explicitly add the
# object files which include the public symbols of the memory functions.
list(REMOVE_ITEM fq_deps_list ${memory_functions})
list(REMOVE_DUPLICATES fq_deps_list)

# TODO: Instead of gathering internal object files from entrypoints,
# collect the object files with public names of entrypoints.
get_object_files_for_test(
link_object_files skipped_entrypoints_list ${fq_deps_list})
if(skipped_entrypoints_list)
message(STATUS "Skipping ${fq_target_name} as it has skipped deps.")
return()
endif()

# Create a sysroot structure
set(sysroot ${CMAKE_CURRENT_BINARY_DIR}/${test_name}/sysroot)
file(MAKE_DIRECTORY ${sysroot})
file(MAKE_DIRECTORY ${sysroot}/include)
set(sysroot_lib ${sysroot}/lib)
file(MAKE_DIRECTORY ${sysroot_lib})
set(startup_object_file $<TARGET_OBJECTS:${INTEGRATION_TEST_STARTUP}>)
set(crti_object_file $<TARGET_OBJECTS:libc.startup.linux.crti>)
set(crtn_object_file $<TARGET_OBJECTS:libc.startup.linux.crtn>)
set(dummy_archive $<TARGET_PROPERTY:libc_integration_test_dummy,ARCHIVE_OUTPUT_DIRECTORY>/lib$<TARGET_PROPERTY:libc_integration_test_dummy,ARCHIVE_OUTPUT_NAME>.a)
# TODO: Copy the startup files to the correct target-triple directory instead
# of to a partly hard-coded directory.
set(startup_dst ${sysroot_lib}/${LIBC_TARGET_ARCHITECTURE}-linux-gnu)
add_custom_command(
OUTPUT ${startup_dst} ${sysroot}/lib/crti.o ${sysroot}/lib/crtn.o ${sysroot}/lib/libm.a ${sysroot}/lib/libc++.a
COMMAND cmake -E copy ${startup_object_file} ${startup_dst}/$<TARGET_PROPERTY:${INTEGRATION_TEST_STARTUP},OUTPUT_NAME>
COMMAND cmake -E copy ${crti_object_file} ${sysroot_lib}/$<TARGET_PROPERTY:libc.startup.linux.crti,OUTPUT_NAME>
COMMAND cmake -E copy ${crtn_object_file} ${sysroot_lib}/$<TARGET_PROPERTY:libc.startup.linux.crtn,OUTPUT_NAME>
# We copy the dummy archive as libm.a and libc++.a as the compiler drivers expect them.
COMMAND cmake -E copy ${dummy_archive} ${sysroot_lib}/libm.a
COMMAND cmake -E copy ${dummy_archive} ${sysroot_lib}/libc++.a
DEPENDS ${INTEGRATION_TEST_STARTUP} libc.startup.linux.crti libc.startup.linux.crtn libc_integration_test_dummy
)
add_custom_target(
${fq_target_name}.__copy_startup__
DEPENDS ${startup_dst}
)

# We add the memory functions objects explicitly. Note that we
# are adding objects of the targets which contain the public
# C symbols. This is because compiler codegen can emit calls to
# the C memory functions.
foreach(func IN LISTS memory_functions)
list(APPEND link_object_files $<TARGET_OBJECTS:${func}>)
endforeach()
list(REMOVE_DUPLICATES link_object_files)

# Make a library of all deps
add_library(
${fq_libc_target_name}
${fq_target_name}.__libc__
STATIC
EXCLUDE_FROM_ALL
${link_object_files}
# We add the memory functions objects explicitly. Note that we
# are adding objects of the targets which contain the public
# C symbols. This is because compiler codegen can emit calls to
# the C memory functions.
$<TARGET_OBJECTS:libc.src.string.bcmp>
$<TARGET_OBJECTS:libc.src.string.bzero>
$<TARGET_OBJECTS:libc.src.string.memcmp>
$<TARGET_OBJECTS:libc.src.string.memcpy>
$<TARGET_OBJECTS:libc.src.string.memmove>
$<TARGET_OBJECTS:libc.src.string.memset>
)
set_target_properties(${fq_libc_target_name} PROPERTIES ARCHIVE_OUTPUT_NAME c)
set_target_properties(${fq_libc_target_name} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${sysroot_lib})
set_target_properties(${fq_target_name}.__libc__
PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
set_target_properties(${fq_target_name}.__libc__
PROPERTIES ARCHIVE_OUTPUT_NAME ${fq_target_name}.libc)

set(fq_build_target_name ${fq_target_name}.__build__)
add_executable(
Expand All @@ -523,16 +503,13 @@ function(add_integration_test test_name)
${LIBC_BUILD_DIR}
${LIBC_BUILD_DIR}/include
)
target_compile_options(${fq_build_target_name} PRIVATE -ffreestanding ${INTEGRATION_TEST_COMPILE_OPTIONS})
# We set a number of link options to prevent picking up system libc binaries.
# Also, we restrict the integration tests to fully static executables. The
# rtlib is set to compiler-rt to make the compiler drivers pick up the compiler
# runtime binaries using full paths. Otherwise, files like crtbegin.o are passed
# as is (and not as paths like /usr/lib/.../crtbegin.o).
target_link_options(${fq_build_target_name} PRIVATE --sysroot=${sysroot} -static -stdlib=libc++ --rtlib=compiler-rt)
target_compile_options(${fq_build_target_name}
PRIVATE -ffreestanding ${INTEGRATION_TEST_COMPILE_OPTIONS})
target_link_options(${fq_build_target_name} PRIVATE -nostdlib -static)
target_link_libraries(${fq_build_target_name}
${INTEGRATION_TEST_STARTUP} ${fq_target_name}.__libc__
libc.test.IntegrationTest.test)
add_dependencies(${fq_build_target_name}
${fq_target_name}.__copy_startup__
${fq_libc_target_name}
libc.test.IntegrationTest.test
${INTEGRATION_TEST_DEPENDS})

Expand All @@ -541,6 +518,5 @@ function(add_integration_test test_name)
COMMAND ${INTEGRATION_TEST_ENV} $<TARGET_FILE:${fq_build_target_name}> ${INTEGRATION_TEST_ARGS}
COMMENT "Running integration test ${fq_target_name}"
)

add_dependencies(${INTEGRATION_TEST_SUITE} ${fq_target_name})
endfunction(add_integration_test)
3 changes: 3 additions & 0 deletions libc/startup/linux/aarch64/start.cpp
Expand Up @@ -23,6 +23,9 @@
#include <unistd.h>

extern "C" int main(int, char **, char **);
// The BFD linker requires a reference to __dso_handle to trigger creating
// a symbol for it when -nostdlib is used..
extern "C" void *__dso_handle = nullptr;

// Source documentation:
// https://github.com/ARM-software/abi-aa/tree/main/sysvabi64
Expand Down
3 changes: 3 additions & 0 deletions libc/startup/linux/x86_64/start.cpp
Expand Up @@ -22,6 +22,9 @@
#include <unistd.h>

extern "C" int main(int, char **, char **);
// The BFD linker requires a reference to __dso_handle to trigger creating
// a symbol for it when -nostdlib is used..
extern "C" void *__dso_handle = nullptr;

namespace __llvm_libc {

Expand Down

0 comments on commit a7d869a

Please sign in to comment.