Skip to content

Commit

Permalink
Merge pull request #232 from abeimler/feature/detect-custom-linker
Browse files Browse the repository at this point in the history
Add detection for custom Linker
  • Loading branch information
aminya authored Aug 8, 2023
2 parents 54831cb + 713aaeb commit 8dd8a5d
Show file tree
Hide file tree
Showing 7 changed files with 202 additions and 50 deletions.
9 changes: 8 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -128,4 +128,11 @@ services:
build:
context: .
dockerfile: ./docker/Dockerfile.arm-bare-metal
target: build
target: build
build-gcc-with-custom-linker:
build:
context: .
dockerfile: ./docker/Dockerfile
args:
compiler: gcc
target: build-with-custom-linker
14 changes: 14 additions & 0 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ RUN setup-cpp --compiler $compiler --llvm true --cmake true --doxygen true --nin
COPY ./docker/entrypoint.sh /docker-entrypoint.sh
ENTRYPOINT [ "/docker-entrypoint.sh" ]

FROM setup AS setup-custom-linker

# install linker
RUN apt-get update && apt-get install -y \
binutils \
mold \
lld \
&& rm -rf /var/lib/apt/lists/*

FROM setup AS build
COPY . /home/project_options
Expand All @@ -30,3 +38,9 @@ WORKDIR /home/project_options
RUN git submodule update --init
CMD ["/bin/bash", "-c", "task myproj:test"]


FROM setup-custom-linker AS build-with-custom-linker
COPY . /home/project_options
WORKDIR /home/project_options
RUN git submodule update --init
CMD ["/bin/bash", "-c", "task myproj:build"]
4 changes: 4 additions & 0 deletions docker/Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ tasks:
- docker-compose up --build test-gcc
- docker-compose down

gcc.custom-linker:
- docker-compose up --build build-gcc-with-custom-linker
- docker-compose down

llvm:
- docker-compose up --build build-llvm
- docker-compose up --build test-llvm
Expand Down
118 changes: 116 additions & 2 deletions src/Linker.cmake
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@
include_guard()

# Test linker option support
function(test_linker_option output_linker_test linker)
set(output_linker_test OFF PARENT_SCOPE)
if(NOT "${linker}" STREQUAL "")
include(CheckCXXCompilerFlag)

set(_linker_flag "-fuse-ld=${linker}")

check_cxx_compiler_flag(${_linker_flag} _cxx_supports_linker)
if("${_cxx_supports_linker}" STREQUAL "1")
set(${output_linker_test} ON PARENT_SCOPE)
else()
set(${output_linker_test} OFF PARENT_SCOPE)
endif()
endif()
endfunction()

# Set the linker to use for the linking phase
macro(configure_linker _project_name _linker)
if(NOT "${_linker}" STREQUAL "")
Expand All @@ -8,8 +25,8 @@ macro(configure_linker _project_name _linker)

set(_linker_flag "-fuse-ld=${_linker}")

check_cxx_compiler_flag(${_linker_flag} _cxx_supports_linker)
if("${_cxx_supports_linker}" STREQUAL "1")
test_linker_option(_cxx_supports_linker ${_linker})
if(_cxx_supports_linker)
message(TRACE "Using ${_linker} as the linker for ${_project_name}")
target_link_options(${_project_name} INTERFACE ${_linker_flag})
else()
Expand All @@ -19,3 +36,100 @@ macro(configure_linker _project_name _linker)
endif()
endif()
endmacro()

#[[.rst:

``find_linker``
===============

Find a linker prefering the linkers in this order: sold, mold, lld, gold, the system linker

Output variables:

- ``LINKER``: the linker to use

]]
function(find_linker LINKER)
find_sold(_PROGRAM_sold)
if(_PROGRAM_sold)
set(${LINKER} "sold" PARENT_SCOPE)
return()
endif()

find_mold(_PROGRAM_mold)
if(_PROGRAM_mold)
set(${LINKER} "mold" PARENT_SCOPE)
return()
endif()

find_lld(_PROGRAM_lld)
if(_PROGRAM_lld)
set(${LINKER} "lld" PARENT_SCOPE)
return()
endif()

find_gold(_PROGRAM_gold)
if(_PROGRAM_gold)
set(${LINKER} "gold" PARENT_SCOPE)
return()
endif()

# else, use the default linker
set(${LINKER} "" PARENT_SCOPE)
endfunction()

function(find_sold PROGRAM_sold)
if(UNIX AND NOT WIN32)
find_program(_PROGRAM_sold NAMES "sold")
if(EXISTS ${_PROGRAM_sold})
test_linker_option(SUPPORTS_SOLD "sold")
if(SUPPORTS_SOLD)
set(${PROGRAM_sold} ${_PROGRAM_sold} PARENT_SCOPE)
return()
endif()
endif()
endif()
set(${PROGRAM_sold} OFF PARENT_SCOPE)
endfunction()

function(find_mold PROGRAM_mold)
if(UNIX AND NOT WIN32)
find_program(_PROGRAM_MOLD NAMES "mold")
if(EXISTS ${_PROGRAM_MOLD})
test_linker_option(SUPPORTS_MOLD "mold")
if(SUPPORTS_MOLD)
set(${PROGRAM_mold} ${_PROGRAM_MOLD} PARENT_SCOPE)
return()
endif()
endif()
endif()
set(${PROGRAM_mold} OFF PARENT_SCOPE)
endfunction()

function(find_lld PROGRAM_lld)
if((CMAKE_CXX_COMPILER_ID MATCHES ".*Clang.*"))
find_program(_PROGRAM_LLD NAMES "lld")
if(EXISTS ${_PROGRAM_LLD})
test_linker_option(SUPPORTS_LLD "lld")
if(SUPPORTS_LLD)
set(${PROGRAM_lld} ${_PROGRAM_LLD} PARENT_SCOPE)
return()
endif()
endif()
endif()
set(${PROGRAM_lld} OFF PARENT_SCOPE)
endfunction()

function(find_gold PROGRAM_gold)
if((CMAKE_CXX_COMPILER_ID MATCHES ".*GNU.*") AND NOT WIN32)
find_program(_PROGRAM_GOLD NAMES "gold")
if(EXISTS ${_PROGRAM_GOLD})
test_linker_option(SUPPORTS_GOLD "gold")
if(SUPPORTS_GOLD)
set(${PROGRAM_gold} ${_PROGRAM_GOLD} PARENT_SCOPE)
return()
endif()
endif()
endif()
set(${PROGRAM_gold} OFF PARENT_SCOPE)
endfunction()
55 changes: 53 additions & 2 deletions src/Sanitizers.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@ function(

if(${ENABLE_SANITIZER_ADDRESS})
list(APPEND SANITIZERS "address")
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 8)
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL
8
)
list(APPEND SANITIZERS "pointer-compare" "pointer-subtract")
message(
STATUS
"To enable invalid pointer pairs detection, add detect_invalid_pointer_pairs=2 to the environment variable ASAN_OPTIONS."
"To enable invalid pointer pairs detection, add detect_invalid_pointer_pairs=2 to the environment variable ASAN_OPTIONS."
)
endif()
endif()
Expand Down Expand Up @@ -91,3 +93,52 @@ function(
endif()

endfunction()

# detect sanitizers support for compiler
function(
check_sanitizers_support
ENABLE_SANITIZER_ADDRESS
ENABLE_SANITIZER_UNDEFINED_BEHAVIOR
ENABLE_SANITIZER_LEAK
ENABLE_SANITIZER_THREAD
ENABLE_SANITIZER_MEMORY
)
set(SANITIZERS "")
if(NOT "${CMAKE_SYSTEM_NAME}" STREQUAL "Windows")
list(APPEND SANITIZERS "address")
list(APPEND SANITIZERS "undefined")
list(APPEND SANITIZERS "leak")
list(APPEND SANITIZERS "thread")
list(APPEND SANITIZERS "memory")
elseif(MSVC)
# or it is MSVC and has run vcvarsall
string(FIND "$ENV{PATH}" "$ENV{VSINSTALLDIR}" index_of_vs_install_dir)
if("${index_of_vs_install_dir}" STREQUAL "-1")
list(APPEND SANITIZERS "address")
endif()
endif()

list(JOIN SANITIZERS "," LIST_OF_SANITIZERS)

if(LIST_OF_SANITIZERS)
if(NOT "${LIST_OF_SANITIZERS}" STREQUAL "")
if("address" IN_LIST SANITIZERS)
set(${ENABLE_SANITIZER_ADDRESS} "ENABLE_SANITIZER_ADDRESS" PARENT_SCOPE)
endif()
if("undefined" IN_LIST SANITIZERS)
set(${ENABLE_SANITIZER_UNDEFINED_BEHAVIOR} "ENABLE_SANITIZER_UNDEFINED_BEHAVIOR"
PARENT_SCOPE
)
endif()
if("leak" IN_LIST SANITIZERS)
set(${ENABLE_SANITIZER_LEAK} "ENABLE_SANITIZER_LEAK" PARENT_SCOPE)
endif()
if("thread" IN_LIST SANITIZERS)
set(${ENABLE_SANITIZER_THREAD} "ENABLE_SANITIZER_THREAD" PARENT_SCOPE)
endif()
if("memory" IN_LIST SANITIZERS)
set(${ENABLE_SANITIZER_MEMORY} "ENABLE_SANITIZER_MEMORY" PARENT_SCOPE)
endif()
endif()
endif()
endfunction()
45 changes: 0 additions & 45 deletions src/Utilities.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -124,48 +124,3 @@ function(detect_architecture arch)
set(${arch} x64 PARENT_SCOPE)
endif()
endfunction()

# detect sanitizers support for compiler
function(check_sanitizers_support
ENABLE_SANITIZER_ADDRESS
ENABLE_SANITIZER_UNDEFINED_BEHAVIOR
ENABLE_SANITIZER_LEAK
ENABLE_SANITIZER_THREAD
ENABLE_SANITIZER_MEMORY)
set(SANITIZERS "")
if(NOT "${CMAKE_SYSTEM_NAME}" STREQUAL "Windows")
list(APPEND SANITIZERS "address")
list(APPEND SANITIZERS "undefined")
list(APPEND SANITIZERS "leak")
list(APPEND SANITIZERS "thread")
list(APPEND SANITIZERS "memory")
elseif(MSVC)
# or it is MSVC and has run vcvarsall
string(FIND "$ENV{PATH}" "$ENV{VSINSTALLDIR}" index_of_vs_install_dir)
if("${index_of_vs_install_dir}" STREQUAL "-1")
list(APPEND SANITIZERS "address")
endif()
endif()

list(JOIN SANITIZERS "," LIST_OF_SANITIZERS)

if(LIST_OF_SANITIZERS)
if(NOT "${LIST_OF_SANITIZERS}" STREQUAL "")
if("address" IN_LIST SANITIZERS)
set(${ENABLE_SANITIZER_ADDRESS} "ENABLE_SANITIZER_ADDRESS" PARENT_SCOPE)
endif()
if("undefined" IN_LIST SANITIZERS)
set(${ENABLE_SANITIZER_UNDEFINED_BEHAVIOR} "ENABLE_SANITIZER_UNDEFINED_BEHAVIOR" PARENT_SCOPE)
endif()
if("leak" IN_LIST SANITIZERS)
set(${ENABLE_SANITIZER_LEAK} "ENABLE_SANITIZER_LEAK" PARENT_SCOPE)
endif()
if("thread" IN_LIST SANITIZERS)
set(${ENABLE_SANITIZER_THREAD} "ENABLE_SANITIZER_THREAD" PARENT_SCOPE)
endif()
if("memory" IN_LIST SANITIZERS)
set(${ENABLE_SANITIZER_MEMORY} "ENABLE_SANITIZER_MEMORY" PARENT_SCOPE)
endif()
endif()
endif()
endfunction()
7 changes: 7 additions & 0 deletions tests/myproj/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ check_sanitizers_support(ENABLE_SANITIZER_ADDRESS
ENABLE_SANITIZER_THREAD
ENABLE_SANITIZER_MEMORY)

# Detect custom linker
if(NOT MSVC)
find_linker(LINKER)
#message(STATUS "Detect Linker: ${LINKER}")
endif()

# Initialize project_options
# uncomment the options to enable them
project_options(
Expand Down Expand Up @@ -66,6 +72,7 @@ project_options(
# ${ENABLE_SANITIZER_THREAD}
# ${ENABLE_SANITIZER_MEMORY}
# CLANG_WARNINGS "-Weverything"
LINKER "${LINKER}"
)
# NOTE: project_options and project_warnings are defined inside project_options

Expand Down

0 comments on commit 8dd8a5d

Please sign in to comment.