-
Notifications
You must be signed in to change notification settings - Fork 0
/
RelocCPPGenerate.cmake
204 lines (166 loc) · 6.74 KB
/
RelocCPPGenerate.cmake
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# SPDX-FileCopyrightText: Fondazione Istituto Italiano di Tecnologia (IIT)
# SPDX-License-Identifier: BSD-3-Clause
# reloc_cpp_generate(<library>
# GENERATED_HEADER <generated_header>
# GENERATED_FUNCTION <generated_function>
# DISABLE_RELOCATABLE <disable_relocatable>
# EXPORT_MACRO_INCLUDE <export_macro_include>
# EXPORT_MACRO_NAME <export_macro_name>
# VERBOSE <verbose>)
#
function(RELOC_CPP_GENERATE _library)
set(_options)
set(_oneValueArgs
GENERATED_HEADER
GENERATED_FUNCTION
DISABLE_RELOCATABLE
EXPORT_MACRO_INCLUDE
EXPORT_MACRO_NAME
VERBOSE
)
set(_multiValueArgs )
cmake_parse_arguments(RCG "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN} )
if(NOT DEFINED RCG_GENERATED_HEADER)
message(FATAL_ERROR "reloc_cpp_generate: missing parameter GENERATED_HEADER")
endif()
if(NOT DEFINED RCG_GENERATED_FUNCTION)
message(FATAL_ERROR "reloc_cpp_generate: missing parameter GENERATED_FUNCTION")
endif()
if(DEFINED RCG_EXPORT_MACRO_INCLUDE)
set(RCG_EXPORT_MACRO_INCLUDE_LINE "#include <${RCG_EXPORT_MACRO_INCLUDE}>")
else()
set(RCG_EXPORT_MACRO_INCLUDE_LINE "")
endif()
if(DEFINED RCG_EXPORT_MACRO_NAME)
set(RCG_EXPORT_MACRO_NAME "")
endif()
if(DEFINED RCG_EXPORT_MACRO_NAME)
set(RCG_EXPORT_MACRO_NAME_WITH_SPACE "${RCG_EXPORT_MACRO_NAME} ")
else()
set(RCG_EXPORT_MACRO_NAME_WITH_SPACE "${RCG_EXPORT_MACRO_NAME}")
endif()
if(NOT TARGET ${_library})
message(FATAL_ERROR "reloc_cpp_generate: library ${_library} does not exist")
endif()
if(NOT TARGET ${_library})
message(FATAL_ERROR "reloc_cpp_generate: library ${_library} does not exist")
endif()
get_target_property(target_type ${_library} TYPE)
if(NOT (target_type STREQUAL "STATIC_LIBRARY" OR target_type STREQUAL "MODULE_LIBRARY" OR target_type STREQUAL "SHARED_LIBRARY"))
message(FATAL_ERROR "reloc_cpp_generate: library ${_library} is of unsupported type ${target_type}")
endif()
# Get generated .cpp name
get_filename_component(RCG_GENERATED_HEADER_DIRECTORY ${RCG_GENERATED_HEADER} DIRECTORY)
get_filename_component(RCG_GENERATED_HEADER_NAME_WE ${RCG_GENERATED_HEADER} NAME_WE)
get_filename_component(RCG_GENERATED_HEADER_NAME ${RCG_GENERATED_HEADER} NAME)
set(RCG_GENERATED_CPP ${RCG_GENERATED_HEADER_DIRECTORY}/${RCG_GENERATED_HEADER_NAME_WE}.cpp)
if (DEFINED RCG_VERBOSE AND RCG_VERBOSE)
message(STATUS "reloc_cpp_generate: RCG_GENERATED_CPP=${RCG_GENERATED_CPP}")
endif()
# Decompose scoped function name in unscoped name and namespaces
string(REPLACE "::" ";" RCG_GENERATED_FUNCTION_NAMESPACES ${RCG_GENERATED_FUNCTION})
list(POP_BACK RCG_GENERATED_FUNCTION_NAMESPACES RCG_GENERATED_FUNCTION_UNSCOPED)
# Generate namespace-related lines
set(RCG_HEADER_OPEN_NAMESPACES "")
set(RCG_HEADER_CLOSE_NAMESPACES "")
foreach(RCG_NAMESPACE IN ITEMS ${RCG_GENERATED_FUNCTION_NAMESPACES})
string(APPEND RCG_HEADER_OPEN_NAMESPACES "namespace ${RCG_NAMESPACE} {\n")
string(APPEND RCG_HEADER_CLOSE_NAMESPACES "}\n")
endforeach()
# Write header
file(GENERATE OUTPUT "${RCG_GENERATED_HEADER}"
CONTENT
"// This file is automatically generated reloc_cpp_generate CMake function.
#pragma once
#include <optional>
#include <string>
${RCG_EXPORT_MACRO_INCLUDE_LINE}
${RCG_HEADER_OPEN_NAMESPACES}
${RCG_EXPORT_MACRO_NAME_WITH_SPACE}std::optional<std::string> ${RCG_GENERATED_FUNCTION_UNSCOPED}();
${RCG_HEADER_CLOSE_NAMESPACES}
")
# Write cpp for shared or module library type
if (target_type STREQUAL "MODULE_LIBRARY" OR target_type STREQUAL "SHARED_LIBRARY" AND NOT RCG_DISABLE_RELOCATABLE)
# We can't query the LOCATION property of the target due to https://cmake.org/cmake/help/v3.25/policy/CMP0026.html
# We can only access the directory of the library at generation time via $<TARGET_FILE_DIR:tgt>
file(GENERATE OUTPUT "${RCG_GENERATED_CPP}"
CONTENT
"// This file is automatically generated reloc_cpp_generate CMake function.
#include \"${RCG_GENERATED_HEADER_NAME}\"
#include <filesystem>
#ifdef _WIN32
#include <windows.h>
#else
#include <dlfcn.h>
#endif
#include <iostream>
std::optional<std::string> ${RCG_GENERATED_FUNCTION}()
{
std::error_code fs_error;
// Get location of the library
std::filesystem::path library_location;
#ifndef _WIN32
Dl_info address_info;
int res_val = dladdr(reinterpret_cast<void *>(&${RCG_GENERATED_FUNCTION}), &address_info);
if (address_info.dli_fname && res_val > 0)
{
library_location = address_info.dli_fname;
}
else
{
return {};
}
#else
// See
char module_path[MAX_PATH];
HMODULE hm = NULL;
if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
(LPCSTR) &${RCG_GENERATED_FUNCTION}, &hm) == 0)
{
return {};
}
if (GetModuleFileNameA(hm, module_path, sizeof(module_path)) == 0)
{
return {};
}
library_location = std::string(module_path);
#endif
const std::filesystem::path library_directory = library_location.parent_path();
// Given the library_directory, return the install prefix via the relative path
#ifndef _WIN32
const std::filesystem::path rel_path_from_install_prefix_to_lib = std::string(\"${CMAKE_INSTALL_LIBDIR}\");
#else
const std::filesystem::path rel_path_from_install_prefix_to_lib = std::string(\"${CMAKE_INSTALL_BINDIR}\");
#endif
const std::filesystem::path rel_path_from_lib_to_install_prefix =
std::filesystem::relative(std::filesystem::current_path(), std::filesystem::current_path() / rel_path_from_install_prefix_to_lib, fs_error);
// TODO(traversaro): handle fs_error errors
const std::filesystem::path install_prefix = library_directory / rel_path_from_lib_to_install_prefix;
const std::filesystem::path install_prefix_canonical = std::filesystem::canonical(install_prefix, fs_error);
// TODO(traversaro): handle fs_error errors
// Return install prefix
return install_prefix_canonical.string();
}
")
else()
# For static library, fallback to just provide return CMAKE_INSTALL_PREFIX
file(GENERATE OUTPUT "${RCG_GENERATED_CPP}"
CONTENT
"// This file is automatically generated reloc_cpp_generate CMake function.
#include \"${RCG_GENERATED_HEADER_NAME}\"
std::optional<std::string> ${RCG_GENERATED_FUNCTION}()
{
return \"${CMAKE_INSTALL_PREFIX}\";
}
")
endif()
# Add cpp to library
target_sources(${_library} PRIVATE ${RCG_GENERATED_CPP})
# Specify that we need C++17 features
target_compile_features(${_library} PUBLIC cxx_std_17)
# Link dl due to the use of dladdr
if(NOT WIN32)
target_link_libraries(${_library} PRIVATE ${CMAKE_DL_LIBS})
endif()
endfunction()