forked from ruslo/hunter
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathautotools-merge-lipo.cmake.in
245 lines (222 loc) · 7.26 KB
/
autotools-merge-lipo.cmake.in
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
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
# Copyright (c) 2015 Ruslan Baratov, Alexandre Pretyman
# All rights reserved.
### Input params check
string(COMPARE EQUAL "@multi_arch_install_root@" "" is_empty)
if(is_empty)
message(FATAL_ERROR "multi_arch_install_root is empty")
endif()
string(COMPARE EQUAL "@ios_architectures@" "" is_empty)
if(is_empty)
message(FATAL_ERROR "ios_architectures is empty")
endif()
string(COMPARE EQUAL "@HUNTER_PACKAGE_INSTALL_PREFIX@" "" is_empty)
if(is_empty)
message(FATAL_ERROR "HUNTER_PACKAGE_INSTALL_PREFIX is empty")
endif()
set(ios_architectures @ios_architectures@)
set(built_arch_roots)
foreach(x ${ios_architectures})
list(APPEND built_arch_roots @multi_arch_install_root@/${x})
endforeach()
list(LENGTH ios_architectures total_arch_number)
# We work with the first root path: we move everything, except the *.a static
# library files into @HUNTER_PACKAGE_INSTALL_PREFIX@, then we lipo the static
# libraries together into @HUNTER_PACKAGE_INSTALL_PREFIX@
list(GET built_arch_roots 0 first_built_root)
file(GLOB_RECURSE
binary_files
RELATIVE
"${first_built_root}"
${first_built_root}/*
)
file(GLOB_RECURSE
libtool_la_files
RELATIVE
"${first_built_root}"
${first_built_root}/lib/*.la
)
file(GLOB_RECURSE
text_files
RELATIVE
"${first_built_root}"
${first_built_root}/include/*
)
# Remove all libtool_la_files from all built roots
foreach(arch ${ios_architectures})
foreach(file_name ${libtool_la_files})
file(REMOVE
"@multi_arch_install_root@/${arch}/${file_name}"
)
endforeach()
endforeach()
# Exclude text files and .la files from binaries list
foreach(x ${libtool_la_files})
list(REMOVE_ITEM binary_files ${x})
endforeach()
foreach(x ${text_files})
list(REMOVE_ITEM binary_files ${x})
endforeach()
# The preprocessor macros below are from
# http://sourceforge.net/p/predef/wiki/Architectures/
# except armv7, which was taken from:
# clang -arch armv7 -dD -E config.h
function(preprocessor_macro arch result)
if(${arch} STREQUAL "armv7")
set(${result} "__ARM_ARCH_7A__" PARENT_SCOPE)
elseif(${arch} STREQUAL "armv7s")
set(${result} "__ARM_ARCH_7S__" PARENT_SCOPE)
elseif(${arch} STREQUAL "arm64")
set(${result} "__aarch64__" PARENT_SCOPE)
elseif(${arch} STREQUAL "i386")
set(${result} "__i386__" PARENT_SCOPE)
elseif(${arch} STREQUAL "x86_64")
set(${result} "__x86_64__" PARENT_SCOPE)
else()
message(FATAL_ERROR "Architecture: ${arch} is not supported")
endif()
endfunction()
# List the different roots which ${file_name} differ from
# ${first_built_root} and store them in result
# If result is an empty list, all files are equal
set(built_arch_roots_except_first ${built_arch_roots})
list(REMOVE_AT built_arch_roots_except_first 0)
function(list_roots_file_diff file_name result)
# make different_roots a list, so it can be printed for better investigation
set(different_roots)
foreach(built_arch_root ${built_arch_roots_except_first})
file(DIFFERENT
is_different
FILES
"${first_built_root}/${file_name}"
"${built_arch_root}/${file_name}"
)
if(is_different)
list(APPEND different_roots "${built_arch_root}/${file_name}")
endif()
endforeach()
set(${result} ${different_roots} PARENT_SCOPE)
endfunction()
# Function is used when the files of all archs are the same, move
# one file to the final destination and delete the others.
function(move_one_delete_other file_name)
file(RENAME
"${first_built_root}/${file_name}"
"@HUNTER_PACKAGE_INSTALL_PREFIX@/${file_name}"
)
# Remove the unneeded copies
foreach(built_arch_root ${built_arch_roots_except_first})
file(REMOVE "${built_arch_root}/${file_name}")
endforeach()
endfunction()
# Merge a header file that differed in content when the project was built with
# different architectures. Guard its contents with #ifdef #elif to guarantee
# that each architecture gets only its file
function(merge_header_diff_archs file_name)
set(merged_file_contents "
/******************************************************
* File auto generated by Hunter by merging file: *
* ${file_name}
* which differed its contents in a multi-arch build. *
* The supported architectures are: *
* ${ios_architectures}
*****************************************************/\n"
)
set(arch_counter 1)
foreach(arch ${ios_architectures})
set(full_path_file_name
"@multi_arch_install_root@/${arch}/${file_name}"
)
preprocessor_macro(${arch} arch_define)
if (arch_counter EQUAL 1)
set(merged_file_contents
"${merged_file_contents}\n#ifdef ${arch_define}\n"
)
else()
set(merged_file_contents
"${merged_file_contents}\n#elif ${arch_define}\n"
)
endif()
if(EXISTS "${full_path_file_name}")
file(READ
${full_path_file_name}
file_contents
)
else()
set(file_contents "")
endif()
# Append contents to the merged file
set(merged_file_contents
"${merged_file_contents}${file_contents}"
)
# Discard the file
file(REMOVE
${full_path_file_name}
)
if (${arch_counter} EQUAL ${total_arch_number})
set(merged_file_contents
"${merged_file_contents}
#else
# error Architecture not supported. It is not one of ${ios_architectures}
#endif\n"
)
endif()
math(EXPR arch_counter ${arch_counter}+1)
endforeach()
file(WRITE
"@HUNTER_PACKAGE_INSTALL_PREFIX@/${file_name}"
"${merged_file_contents}"
)
endfunction()
# Compare for differences between files in built_arch_roots
# If files are different and are in the include/ directory
# they are merged with #ifdef guards
foreach(file_name ${text_files})
get_filename_component(final_dir
"@HUNTER_PACKAGE_INSTALL_PREFIX@/${file_name}"
DIRECTORY
)
file(MAKE_DIRECTORY ${final_dir})
# List the arch roots where the file is different
list_roots_file_diff(${file_name} different_roots)
list(LENGTH different_roots len)
if(${len} EQUAL 0)
# Files are the same, so we move them to @HUNTER_PACKAGE_INSTALL_PREFIX@
move_one_delete_other("${file_name}")
else()
# merge the file contents with #ifdef guards
merge_header_diff_archs(${file_name})
endif()
endforeach()
# we lipo the libraries into @HUNTER_PACKAGE_INSTALL_PREFIX@
foreach(x ${binary_files})
# if the dir to put the library in, does not exist, then create it
# this is needed or else lipo could fail
get_filename_component(dir "@HUNTER_PACKAGE_INSTALL_PREFIX@/${x}" DIRECTORY)
file(MAKE_DIRECTORY "${dir}")
set(input_libraries)
foreach(built_arch_root ${built_arch_roots})
list(APPEND input_libraries ${built_arch_root}/${x})
endforeach()
execute_process(
COMMAND
lipo
-create
${input_libraries}
-o
"@HUNTER_PACKAGE_INSTALL_PREFIX@/${x}"
RESULT_VARIABLE
lipo_result
ERROR_VARIABLE
lipo_error
)
if(NOT ${lipo_result} EQUAL 0)
message(FATAL_ERROR "lipo execution failed: ${lipo_error}")
endif()
file(REMOVE ${input_libraries})
endforeach()
# Check no files left (i.e. all binaries fused by lipo, all headers merged)
file(GLOB_RECURSE files_left "@multi_arch_install_root@/*")
string(COMPARE EQUAL "${files_left}" "" is_empty)
if(NOT is_empty)
message(FATAL_ERROR "Unexpected files: ${files_left}")
endif()