Skip to content

Commit

Permalink
[cmake] WITH_USER_foo properly sandboxes shared libraries (#18027)
Browse files Browse the repository at this point in the history
  • Loading branch information
jwnimmer-tri authored Oct 4, 2022
1 parent 409d23b commit bfb17e2
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 57 deletions.
38 changes: 38 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,8 @@ function(generate_external_repository_file OUTPUT)
endif()
endfunction()

# Symlinks the C++ include path for TARGET as workspace/NAME/include, e.g.
# workspace/eigen/include -> .../build/install/include/eigen3
function(symlink_external_repository_includes NAME TARGET)
if(ARGN)
get_target_property(include_dir ${TARGET} INTERFACE_INCLUDE_DIRECTORIES)
Expand All @@ -385,6 +387,40 @@ function(symlink_external_repository_includes NAME TARGET)
endif()
endfunction()

# Symlinks the C++ libraries for TARGET as workspace/NAME/lib/*, e.g.
# workspace/fmt/lib/libfmt.so.6.1.2 -> .../build/install/lib/fmt/libfmt.so.6.1.2
# workspace/fmt/lib/libfmt.so.6 -> .../build/install/lib/fmt/libfmt.so.6.1.2
function(symlink_external_repository_libs NAME TARGET)
if(ARGN)
foreach(config IN LISTS ARGN)
set(workspace "${CMAKE_CURRENT_BINARY_DIR}/external/${config}/workspace")
file(MAKE_DIRECTORY "${workspace}/${NAME}/lib")
# Link the full library name (i.e., libfmt.so.6.1.2 in the case of shared).
get_target_property(location ${TARGET} LOCATION_${config})
if(NOT location)
message(FATAL_ERROR "Target ${TARGET} has no library in LOCATION_${config}")
endif()
get_filename_component(basename "${location}" NAME)
file(CREATE_LINK "${location}" "${workspace}/${NAME}/lib/${basename}" SYMBOLIC)
# Link the SONAME spelling in case of shared libraries.
# If the basename does not match this pattern, this part is all a no-op.
string(REGEX REPLACE "(\\.so\\.[0-9]+)\\.[0-9]+\\.[0-9]+$" "\\1"
other_basename "${basename}")
string(REGEX REPLACE "(\\.[0-9]+)\\.[0-9]+\\.[0-9]+\\.dylib$" "\\1.dylib"
other_basename "${other_basename}")
file(CREATE_LINK "${location}" "${workspace}/${NAME}/lib/${other_basename}" SYMBOLIC)
endforeach()
else()
if(CMAKE_CONFIGURATION_TYPES)
symlink_external_repository_libs(${NAME} ${TARGET}
${CMAKE_CONFIGURATION_TYPES})
elseif(CMAKE_BUILD_TYPE)
symlink_external_repository_libs(${NAME} ${TARGET}
${CMAKE_BUILD_TYPE})
endif()
endif()
endfunction()

macro(override_repository NAME)
set(repo "${CMAKE_CURRENT_BINARY_DIR}/external/$<CONFIG>/workspace/${NAME}")
list(APPEND BAZEL_OVERRIDE_REPOS --override_repository=${NAME}=${repo})
Expand Down Expand Up @@ -412,6 +448,7 @@ if(WITH_USER_FMT)
find_package(fmt CONFIG REQUIRED)

symlink_external_repository_includes(fmt fmt::fmt)
symlink_external_repository_libs(fmt fmt::fmt)
generate_external_repository_file(fmt/WORKSPACE)
generate_external_repository_file(
fmt/BUILD.bazel
Expand All @@ -432,6 +469,7 @@ if(WITH_USER_SPDLOG)
find_package(spdlog CONFIG REQUIRED)

symlink_external_repository_includes(spdlog spdlog::spdlog)
symlink_external_repository_libs(spdlog spdlog::spdlog)
generate_external_repository_file(spdlog/WORKSPACE)
generate_external_repository_file(
spdlog/BUILD.bazel
Expand Down
44 changes: 3 additions & 41 deletions cmake/external/workspace/conversion.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -4,47 +4,9 @@
# CMake imported targets.

def split_cmake_list(cmake_list_str):
"""Convert a string containing a CMake-style list into a 'proper' list."""
"""Converts a string containing a CMake-style list into a 'proper' list.
In particular, empty strings remain empty `[]`, not 1-element lists `[""]`.
"""
if len(cmake_list_str) == 0:
return []
return cmake_list_str.split(";")

def _is_library_extension(ext):
"""Return True if ext looks like a library extension."""
if ext in ["a", "so", "dylib"]:
return True
if ext.startswith("so."):
return True
if ext.endswith(".dylib"):
return True

return False

def library_to_linkopts(path):
"""Convert absolute path to a library to suitable linkopts."""
opts = []

if not path.startswith("/"):
fail("{} is not an absolute path.".format(path))

dirname, libname = path.rsplit("/", 1)

# Add `-Wl,-rpath,<path>` for `-L<path>`.
# See https://github.com/RobotLocomotion/drake/issues/7387#issuecomment-359952616 # noqa
opts.append("-Wl,-rpath," + dirname)
opts.append("-L" + dirname)

if "." in libname:
ext = libname.split(".", 1)[1]
else:
ext = ""

if not _is_library_extension(ext):
fail("{} does not appear to be a path to a library.".format(path))

if not libname.startswith("lib"):
fail("Name of library {} must start with `lib`.".format(libname))

opts.append("-l" + libname[3:].split(".", 1)[0])

return opts
14 changes: 6 additions & 8 deletions cmake/external/workspace/fmt/BUILD.bazel.in
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,25 @@
load("@drake//tools/install:install.bzl", "install")
load(
"@drake//:cmake/external/workspace/conversion.bzl",
"library_to_linkopts",
"split_cmake_list",
)

FMT_DEFINES = split_cmake_list(
_DEFINES = split_cmake_list(
"$<TARGET_PROPERTY:fmt::fmt,INTERFACE_COMPILE_DEFINITIONS>",
)

FMT_LINKOPTS = library_to_linkopts(
"$<TARGET_LINKER_FILE:fmt::fmt>",
)

cc_library(
name = "fmt",
srcs = glob(
["lib/**"],
allow_empty = False,
),
hdrs = glob(
["include/**"],
allow_empty = False,
),
defines = FMT_DEFINES,
defines = _DEFINES,
includes = ["include"],
linkopts = FMT_LINKOPTS,
visibility = ["//visibility:public"],
)

Expand Down
15 changes: 7 additions & 8 deletions cmake/external/workspace/spdlog/BUILD.bazel.in
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,26 @@
load("@drake//tools/install:install.bzl", "install")
load(
"@drake//:cmake/external/workspace/conversion.bzl",
"library_to_linkopts",
"split_cmake_list",
)

SPDLOG_DEFINES = split_cmake_list(
_DEFINES = split_cmake_list(
"$<TARGET_PROPERTY:spdlog::spdlog,INTERFACE_COMPILE_DEFINITIONS>",
)

SPDLOG_LINKOPTS = library_to_linkopts(
"$<TARGET_LINKER_FILE:spdlog::spdlog>",
)

cc_library(
name = "spdlog",
srcs = glob(
["lib/**"],
allow_empty = False,
),
hdrs = glob(
["include/**"],
allow_empty = False,
),
defines = SPDLOG_DEFINES + ["HAVE_SPDLOG"],
defines = _DEFINES + ["HAVE_SPDLOG"],
includes = ["include"],
linkopts = SPDLOG_LINKOPTS + ["-pthread"],
linkopts = ["-pthread"],
visibility = ["//visibility:public"],
deps = ["@fmt"],
)
Expand Down

0 comments on commit bfb17e2

Please sign in to comment.