mirror of https://github.com/Qiskit/qiskit-aer.git
583 lines
16 KiB
CMake
583 lines
16 KiB
CMake
#.rst:
|
|
#
|
|
# Public Functions
|
|
# ^^^^^^^^^^^^^^^^
|
|
#
|
|
# The following functions are defined:
|
|
#
|
|
# .. cmake:command:: target_link_libraries_with_dynamic_lookup
|
|
#
|
|
# ::
|
|
#
|
|
# target_link_libraries_with_dynamic_lookup(<Target> [<Libraries>])
|
|
#
|
|
#
|
|
# Useful to "weakly" link a loadable module. For example, it should be used
|
|
# when compiling a loadable module when the symbols should be resolve from
|
|
# the run-time environment where the module is loaded, and not a specific
|
|
# system library.
|
|
#
|
|
# Like proper linking, except that the given ``<Libraries>`` are not necessarily
|
|
# linked. Instead, the ``<Target>`` is produced in a manner that allows for
|
|
# symbols unresolved within it to be resolved at runtime, presumably by the
|
|
# given ``<Libraries>``. If such a target can be produced, the provided
|
|
# ``<Libraries>`` are not actually linked.
|
|
#
|
|
# It links a library to a target such that the symbols are resolved at
|
|
# run-time not link-time.
|
|
#
|
|
# The linker is checked to see if it supports undefined
|
|
# symbols when linking a shared library. If it does then the library
|
|
# is not linked when specified with this function.
|
|
#
|
|
# On platforms that do not support weak-linking, this function works just
|
|
# like ``target_link_libraries``.
|
|
#
|
|
# .. note::
|
|
#
|
|
# For OSX it uses ``undefined dynamic_lookup``. This is similar to using
|
|
# ``-shared`` on Linux where undefined symbols are ignored.
|
|
#
|
|
# For more details, see `blog <http://blog.tim-smith.us/2015/09/python-extension-modules-os-x/>`_
|
|
# from Tim D. Smith.
|
|
#
|
|
#
|
|
# .. cmake:command:: check_dynamic_lookup
|
|
#
|
|
# Check if the linker requires a command line flag to allow leaving symbols
|
|
# unresolved when producing a target of type ``<TargetType>`` that is
|
|
# weakly-linked against a dependency of type ``<LibType>``.
|
|
#
|
|
# ``<TargetType>``
|
|
# can be one of "STATIC", "SHARED", "MODULE", or "EXE".
|
|
#
|
|
# ``<LibType>``
|
|
# can be one of "STATIC", "SHARED", or "MODULE".
|
|
#
|
|
# Long signature:
|
|
#
|
|
# ::
|
|
#
|
|
# check_dynamic_lookup(<TargetType>
|
|
# <LibType>
|
|
# <ResultVar>
|
|
# [<LinkFlagsVar>])
|
|
#
|
|
#
|
|
# Short signature:
|
|
#
|
|
# ::
|
|
#
|
|
# check_dynamic_lookup(<ResultVar>) # <TargetType> set to "MODULE"
|
|
# # <LibType> set to "SHARED"
|
|
#
|
|
#
|
|
# The result is cached between invocations and recomputed only when the value
|
|
# of CMake's linker flag list changes; ``CMAKE_STATIC_LINKER_FLAGS`` if
|
|
# ``<TargetType>`` is "STATIC", and ``CMAKE_SHARED_LINKER_FLAGS`` otherwise.
|
|
#
|
|
#
|
|
# Defined variables:
|
|
#
|
|
# ``<ResultVar>``
|
|
# Whether the current C toolchain supports weak-linking for target binaries of
|
|
# type ``<TargetType>`` that are weakly-linked against a dependency target of
|
|
# type ``<LibType>``.
|
|
#
|
|
# ``<LinkFlagsVar>``
|
|
# List of flags to add to the linker command to produce a working target
|
|
# binary of type ``<TargetType>`` that is weakly-linked against a dependency
|
|
# target of type ``<LibType>``.
|
|
#
|
|
# ``HAS_DYNAMIC_LOOKUP_<TargetType>_<LibType>``
|
|
# Cached, global alias for ``<ResultVar>``
|
|
#
|
|
# ``DYNAMIC_LOOKUP_FLAGS_<TargetType>_<LibType>``
|
|
# Cached, global alias for ``<LinkFlagsVar>``
|
|
#
|
|
#
|
|
# Private Functions
|
|
# ^^^^^^^^^^^^^^^^^
|
|
#
|
|
# The following private functions are defined:
|
|
#
|
|
# .. warning:: These functions are not part of the scikit-build API. They
|
|
# exist purely as an implementation detail and may change from version
|
|
# to version without notice, or even be removed.
|
|
#
|
|
# We mean it.
|
|
#
|
|
#
|
|
# .. cmake:command:: _get_target_type
|
|
#
|
|
# ::
|
|
#
|
|
# _get_target_type(<ResultVar> <Target>)
|
|
#
|
|
#
|
|
# Shorthand for querying an abbreviated version of the target type
|
|
# of the given ``<Target>``.
|
|
#
|
|
# ``<ResultVar>`` is set to:
|
|
#
|
|
# - "STATIC" for a STATIC_LIBRARY,
|
|
# - "SHARED" for a SHARED_LIBRARY,
|
|
# - "MODULE" for a MODULE_LIBRARY,
|
|
# - and "EXE" for an EXECUTABLE.
|
|
#
|
|
# Defined variables:
|
|
#
|
|
# ``<ResultVar>``
|
|
# The abbreviated version of the ``<Target>``'s type.
|
|
#
|
|
#
|
|
# .. cmake:command:: _test_weak_link_project
|
|
#
|
|
# ::
|
|
#
|
|
# _test_weak_link_project(<TargetType>
|
|
# <LibType>
|
|
# <ResultVar>
|
|
# <LinkFlagsVar>)
|
|
#
|
|
#
|
|
# Attempt to compile and run a test project where a target of type
|
|
# ``<TargetType>`` is weakly-linked against a dependency of type ``<LibType>``:
|
|
#
|
|
# - ``<TargetType>`` can be one of "STATIC", "SHARED", "MODULE", or "EXE".
|
|
# - ``<LibType>`` can be one of "STATIC", "SHARED", or "MODULE".
|
|
#
|
|
# Defined variables:
|
|
#
|
|
# ``<ResultVar>``
|
|
# Whether the current C toolchain can produce a working target binary of type
|
|
# ``<TargetType>`` that is weakly-linked against a dependency target of type
|
|
# ``<LibType>``.
|
|
#
|
|
# ``<LinkFlagsVar>``
|
|
# List of flags to add to the linker command to produce a working target
|
|
# binary of type ``<TargetType>`` that is weakly-linked against a dependency
|
|
# target of type ``<LibType>``.
|
|
#
|
|
|
|
function(_get_target_type result_var target)
|
|
set(target_type "SHARED_LIBRARY")
|
|
if(TARGET ${target})
|
|
get_property(target_type TARGET ${target} PROPERTY TYPE)
|
|
endif()
|
|
|
|
set(result "STATIC")
|
|
|
|
if(target_type STREQUAL "STATIC_LIBRARY")
|
|
set(result "STATIC")
|
|
endif()
|
|
|
|
if(target_type STREQUAL "SHARED_LIBRARY")
|
|
set(result "SHARED")
|
|
endif()
|
|
|
|
if(target_type STREQUAL "MODULE_LIBRARY")
|
|
set(result "MODULE")
|
|
endif()
|
|
|
|
if(target_type STREQUAL "EXECUTABLE")
|
|
set(result "EXE")
|
|
endif()
|
|
|
|
set(${result_var} ${result} PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
|
|
function(_test_weak_link_project
|
|
target_type
|
|
lib_type
|
|
can_weak_link_var
|
|
project_name)
|
|
|
|
set(gnu_ld_ignore "-Wl,--unresolved-symbols=ignore-all")
|
|
set(osx_dynamic_lookup "-undefined dynamic_lookup")
|
|
set(no_flag "")
|
|
|
|
foreach(link_flag_spec gnu_ld_ignore osx_dynamic_lookup no_flag)
|
|
set(link_flag "${${link_flag_spec}}")
|
|
|
|
set(test_project_dir "${PROJECT_BINARY_DIR}/CMakeTmp")
|
|
set(test_project_dir "${test_project_dir}/${project_name}")
|
|
set(test_project_dir "${test_project_dir}/${link_flag_spec}")
|
|
set(test_project_dir "${test_project_dir}/${target_type}")
|
|
set(test_project_dir "${test_project_dir}/${lib_type}")
|
|
|
|
set(test_project_src_dir "${test_project_dir}/src")
|
|
set(test_project_bin_dir "${test_project_dir}/build")
|
|
|
|
file(MAKE_DIRECTORY ${test_project_src_dir})
|
|
file(MAKE_DIRECTORY ${test_project_bin_dir})
|
|
|
|
set(mod_type "STATIC")
|
|
set(link_mod_lib TRUE)
|
|
set(link_exe_lib TRUE)
|
|
set(link_exe_mod FALSE)
|
|
|
|
if("${target_type}" STREQUAL "EXE")
|
|
set(link_exe_lib FALSE)
|
|
set(link_exe_mod TRUE)
|
|
else()
|
|
set(mod_type "${target_type}")
|
|
endif()
|
|
|
|
if("${mod_type}" STREQUAL "MODULE")
|
|
set(link_mod_lib FALSE)
|
|
endif()
|
|
|
|
|
|
file(WRITE "${test_project_src_dir}/CMakeLists.txt" "
|
|
cmake_minimum_required(VERSION ${CMAKE_VERSION})
|
|
project(${project_name} C)
|
|
|
|
include_directories(${test_project_src_dir})
|
|
|
|
add_library(number ${lib_type} number.c)
|
|
add_library(counter ${mod_type} counter.c)
|
|
")
|
|
|
|
if("${mod_type}" STREQUAL "MODULE")
|
|
file(APPEND "${test_project_src_dir}/CMakeLists.txt" "
|
|
set_target_properties(counter PROPERTIES PREFIX \"\")
|
|
")
|
|
endif()
|
|
|
|
if(link_mod_lib)
|
|
file(APPEND "${test_project_src_dir}/CMakeLists.txt" "
|
|
target_link_libraries(counter number)
|
|
")
|
|
elseif(NOT link_flag STREQUAL "")
|
|
file(APPEND "${test_project_src_dir}/CMakeLists.txt" "
|
|
set_target_properties(counter PROPERTIES LINK_FLAGS \"${link_flag}\")
|
|
")
|
|
endif()
|
|
|
|
file(APPEND "${test_project_src_dir}/CMakeLists.txt" "
|
|
add_executable(main main.c)
|
|
")
|
|
|
|
if(link_exe_lib)
|
|
file(APPEND "${test_project_src_dir}/CMakeLists.txt" "
|
|
target_link_libraries(main number)
|
|
")
|
|
elseif(NOT link_flag STREQUAL "")
|
|
file(APPEND "${test_project_src_dir}/CMakeLists.txt" "
|
|
target_link_libraries(main \"${link_flag}\")
|
|
")
|
|
endif()
|
|
|
|
if(link_exe_mod)
|
|
file(APPEND "${test_project_src_dir}/CMakeLists.txt" "
|
|
target_link_libraries(main counter)
|
|
")
|
|
else()
|
|
file(APPEND "${test_project_src_dir}/CMakeLists.txt" "
|
|
target_link_libraries(main \"${CMAKE_DL_LIBS}\")
|
|
")
|
|
endif()
|
|
|
|
file(WRITE "${test_project_src_dir}/number.c" "
|
|
#include <number.h>
|
|
|
|
static int _number;
|
|
void set_number(int number) { _number = number; }
|
|
int get_number() { return _number; }
|
|
")
|
|
|
|
file(WRITE "${test_project_src_dir}/number.h" "
|
|
#ifndef _NUMBER_H
|
|
#define _NUMBER_H
|
|
extern void set_number(int);
|
|
extern int get_number(void);
|
|
#endif
|
|
")
|
|
|
|
file(WRITE "${test_project_src_dir}/counter.c" "
|
|
#include <number.h>
|
|
int count() {
|
|
int result = get_number();
|
|
set_number(result + 1);
|
|
return result;
|
|
}
|
|
")
|
|
|
|
file(WRITE "${test_project_src_dir}/counter.h" "
|
|
#ifndef _COUNTER_H
|
|
#define _COUNTER_H
|
|
extern int count(void);
|
|
#endif
|
|
")
|
|
|
|
file(WRITE "${test_project_src_dir}/main.c" "
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <number.h>
|
|
")
|
|
|
|
if(NOT link_exe_mod)
|
|
file(APPEND "${test_project_src_dir}/main.c" "
|
|
#include <dlfcn.h>
|
|
")
|
|
endif()
|
|
|
|
file(APPEND "${test_project_src_dir}/main.c" "
|
|
int my_count() {
|
|
int result = get_number();
|
|
set_number(result + 1);
|
|
return result;
|
|
}
|
|
|
|
int main(int argc, char **argv) {
|
|
int result;
|
|
")
|
|
|
|
if(NOT link_exe_mod)
|
|
file(APPEND "${test_project_src_dir}/main.c" "
|
|
void *counter_module;
|
|
int (*count)(void);
|
|
|
|
counter_module = dlopen(\"./counter.so\", RTLD_LAZY | RTLD_GLOBAL);
|
|
if(!counter_module) goto error;
|
|
|
|
count = dlsym(counter_module, \"count\");
|
|
if(!count) goto error;
|
|
")
|
|
endif()
|
|
|
|
file(APPEND "${test_project_src_dir}/main.c" "
|
|
result = count() != 0 ? EXIT_FAILURE :
|
|
my_count() != 1 ? EXIT_FAILURE :
|
|
my_count() != 2 ? EXIT_FAILURE :
|
|
count() != 3 ? EXIT_FAILURE :
|
|
count() != 4 ? EXIT_FAILURE :
|
|
count() != 5 ? EXIT_FAILURE :
|
|
my_count() != 6 ? EXIT_FAILURE : EXIT_SUCCESS;
|
|
")
|
|
|
|
if(NOT link_exe_mod)
|
|
file(APPEND "${test_project_src_dir}/main.c" "
|
|
goto done;
|
|
error:
|
|
fprintf(stderr, \"Error occured:\\n %s\\n\", dlerror());
|
|
result = 1;
|
|
|
|
done:
|
|
if(counter_module) dlclose(counter_module);
|
|
")
|
|
endif()
|
|
|
|
file(APPEND "${test_project_src_dir}/main.c" "
|
|
return result;
|
|
}
|
|
")
|
|
|
|
set(_rpath_arg)
|
|
if(APPLE AND ${CMAKE_VERSION} VERSION_GREATER 2.8.11)
|
|
set(_rpath_arg "-DCMAKE_MACOSX_RPATH='${CMAKE_MACOSX_RPATH}'")
|
|
endif()
|
|
|
|
try_compile(project_compiles
|
|
"${test_project_bin_dir}"
|
|
"${test_project_src_dir}"
|
|
"${project_name}"
|
|
CMAKE_FLAGS
|
|
"-DCMAKE_SHARED_LINKER_FLAGS='${CMAKE_SHARED_LINKER_FLAGS}'"
|
|
"-DCMAKE_ENABLE_EXPORTS=ON"
|
|
${_rpath_arg}
|
|
OUTPUT_VARIABLE compile_output)
|
|
|
|
set(project_works 1)
|
|
set(run_output)
|
|
|
|
if(project_compiles)
|
|
execute_process(COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR}
|
|
"${test_project_bin_dir}/main"
|
|
WORKING_DIRECTORY "${test_project_bin_dir}"
|
|
RESULT_VARIABLE project_works
|
|
OUTPUT_VARIABLE run_output
|
|
ERROR_VARIABLE run_output)
|
|
endif()
|
|
|
|
set(test_description
|
|
"Weak Link ${target_type} -> ${lib_type} (${link_flag_spec})")
|
|
|
|
if(project_works EQUAL 0)
|
|
set(project_works TRUE)
|
|
message(STATUS "Performing Test ${test_description} - Success")
|
|
else()
|
|
set(project_works FALSE)
|
|
message(STATUS "Performing Test ${test_description} - Failed")
|
|
file(APPEND ${CMAKE_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/CMakeError.log
|
|
"Performing Test ${test_description} failed with the "
|
|
"following output:\n"
|
|
"BUILD\n-----\n${compile_output}\nRUN\n---\n${run_output}\n")
|
|
endif()
|
|
|
|
set(${can_weak_link_var} ${project_works} PARENT_SCOPE)
|
|
if(project_works)
|
|
set(${project_name} ${link_flag} PARENT_SCOPE)
|
|
break()
|
|
endif()
|
|
endforeach()
|
|
endfunction()
|
|
|
|
function(check_dynamic_lookup)
|
|
# Two signatures are supported:
|
|
|
|
if(ARGC EQUAL "1")
|
|
#
|
|
# check_dynamic_lookup(<ResultVar>)
|
|
#
|
|
set(target_type "MODULE")
|
|
set(lib_type "SHARED")
|
|
set(has_dynamic_lookup_var "${ARGV0}")
|
|
set(link_flags_var "unused")
|
|
|
|
elseif(ARGC GREATER "2")
|
|
#
|
|
# check_dynamic_lookup(<TargetType>
|
|
# <LibType>
|
|
# <ResultVar>
|
|
# [<LinkFlagsVar>])
|
|
#
|
|
set(target_type "${ARGV0}")
|
|
set(lib_type "${ARGV1}")
|
|
set(has_dynamic_lookup_var "${ARGV2}")
|
|
if(ARGC EQUAL "3")
|
|
set(link_flags_var "unused")
|
|
else()
|
|
set(link_flags_var "${ARGV3}")
|
|
endif()
|
|
else()
|
|
message(FATAL_ERROR "missing arguments")
|
|
endif()
|
|
|
|
_check_dynamic_lookup(
|
|
${target_type}
|
|
${lib_type}
|
|
${has_dynamic_lookup_var}
|
|
${link_flags_var}
|
|
)
|
|
set(${has_dynamic_lookup_var} ${${has_dynamic_lookup_var}} PARENT_SCOPE)
|
|
if(NOT "x${link_flags_var}x" STREQUAL "xunusedx")
|
|
set(${link_flags_var} ${${link_flags_var}} PARENT_SCOPE)
|
|
endif()
|
|
endfunction()
|
|
|
|
function(_check_dynamic_lookup
|
|
target_type
|
|
lib_type
|
|
has_dynamic_lookup_var
|
|
link_flags_var
|
|
)
|
|
|
|
# hash the CMAKE_FLAGS passed and check cache to know if we need to rerun
|
|
if("${target_type}" STREQUAL "STATIC")
|
|
string(MD5 cmake_flags_hash "${CMAKE_STATIC_LINKER_FLAGS}")
|
|
else()
|
|
string(MD5 cmake_flags_hash "${CMAKE_SHARED_LINKER_FLAGS}")
|
|
endif()
|
|
|
|
set(cache_var "HAS_DYNAMIC_LOOKUP_${target_type}_${lib_type}")
|
|
set(cache_hash_var "HAS_DYNAMIC_LOOKUP_${target_type}_${lib_type}_hash")
|
|
set(result_var "DYNAMIC_LOOKUP_FLAGS_${target_type}_${lib_type}")
|
|
|
|
if( NOT DEFINED ${cache_hash_var}
|
|
OR NOT "${${cache_hash_var}}" STREQUAL "${cmake_flags_hash}")
|
|
unset(${cache_var} CACHE)
|
|
endif()
|
|
|
|
if(NOT DEFINED ${cache_var})
|
|
set(skip_test FALSE)
|
|
|
|
if(CMAKE_CROSSCOMPILING AND NOT CMAKE_CROSSCOMPILING_EMULATOR)
|
|
set(skip_test TRUE)
|
|
endif()
|
|
|
|
if(skip_test)
|
|
set(has_dynamic_lookup FALSE)
|
|
set(link_flags)
|
|
else()
|
|
_test_weak_link_project(${target_type}
|
|
${lib_type}
|
|
has_dynamic_lookup
|
|
link_flags)
|
|
endif()
|
|
|
|
set(caveat " (when linking ${target_type} against ${lib_type})")
|
|
|
|
set(${cache_var} "${has_dynamic_lookup}"
|
|
CACHE BOOL
|
|
"linker supports dynamic lookup for undefined symbols${caveat}")
|
|
mark_as_advanced(${cache_var})
|
|
|
|
set(${result_var} "${link_flags}"
|
|
CACHE STRING
|
|
"linker flags for dynamic lookup${caveat}")
|
|
mark_as_advanced(${result_var})
|
|
|
|
set(${cache_hash_var} "${cmake_flags_hash}"
|
|
CACHE INTERNAL "hashed flags for ${cache_var} check")
|
|
endif()
|
|
|
|
set(${has_dynamic_lookup_var} "${${cache_var}}" PARENT_SCOPE)
|
|
set(${link_flags_var} "${${result_var}}" PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
function(target_link_libraries_with_dynamic_lookup target)
|
|
_get_target_type(target_type ${target})
|
|
|
|
set(link_props)
|
|
set(link_items)
|
|
set(link_libs)
|
|
|
|
foreach(lib ${ARGN})
|
|
_get_target_type(lib_type ${lib})
|
|
check_dynamic_lookup(${target_type}
|
|
${lib_type}
|
|
has_dynamic_lookup
|
|
dynamic_lookup_flags)
|
|
|
|
if(has_dynamic_lookup)
|
|
if(dynamic_lookup_flags)
|
|
if("${target_type}" STREQUAL "EXE")
|
|
list(APPEND link_items "${dynamic_lookup_flags}")
|
|
else()
|
|
list(APPEND link_props "${dynamic_lookup_flags}")
|
|
endif()
|
|
endif()
|
|
elseif(${lib} MATCHES "(debug|optimized|general)")
|
|
# See gh-255
|
|
else()
|
|
list(APPEND link_libs "${lib}")
|
|
endif()
|
|
endforeach()
|
|
|
|
if(link_props)
|
|
list(REMOVE_DUPLICATES link_props)
|
|
endif()
|
|
|
|
if(link_items)
|
|
list(REMOVE_DUPLICATES link_items)
|
|
endif()
|
|
|
|
if(link_libs)
|
|
list(REMOVE_DUPLICATES link_libs)
|
|
endif()
|
|
|
|
if(link_props)
|
|
set_target_properties(${target}
|
|
PROPERTIES LINK_FLAGS "${link_props}")
|
|
endif()
|
|
|
|
set(links "${link_items}" "${link_libs}")
|
|
if(links)
|
|
target_link_libraries(${target} "${links}")
|
|
endif()
|
|
endfunction()
|
|
|