blob: b2ae9acdcf244fa9ede4319e5a192197d2d39cd5 (
plain)
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
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
|
#!/bin/bash
# extract folder name containing file
#
# param ${1} file name
# return folder name
extract_folder_name() {
# return name of the file until last '/'
echo "$(echo "${1}" | rev | cut -d '/' -f 2- | rev)"
}
# extract all includes found in source files found in the same folder as specified Makefile.am
#
# param ${1} path to a Makefile.am
# return all dependencies libs in the order of compilation
extract_includes() {
# extract folder name from current library Makefile.am
CURRENT_FOLDER=$(extract_folder_name "${1}")"/"
# select only files in current folder
SEARCH_FILES=$(echo "${FILE_LIST}" | grep "${CURRENT_FOLDER}")
# select all lines containing '#include ' directive
RAW_INCLUDES_LIST=$(echo "${SEARCH_FILES}" | xargs grep "^#include " 2>/dev/null)
# filter only included dependencies found in other libraries by using the form 'other_lib_name/header_file.h'
# to do this it is required to select the string between '<' and '>', searching for '/' character and returning the name until last '/'
RAW_INCLUDES_LIST=$(echo "${RAW_INCLUDES_LIST}" | cut -d "#" -f 2 | tr "\"" " " | cut -d "<" -f 2 | cut -d ">" -f 1 | grep "\/" | rev | cut -d "/" -f 2 | rev | sort | uniq)
# filter includes that are not compiled by the project's Makefiles
INCLUDES_LIST=
for i in ${LIBRARIES_LIST}; do
for j in ${RAW_INCLUDES_LIST}; do
if test "${j}" = "${i}"; then
INCLUDES_LIST="${i} ${INCLUDES_LIST}"
break
fi
done
done
# remove empty spaces
INCLUDES_LIST=$(echo ${INCLUDES_LIST} | tr -s " ")
# order dependencies in the order of compilation
FILTERED_INCLUDES_LIST=
for i in ${LIBRARIES_LIST}; do
if test $(echo "${INCLUDES_LIST}" | grep "\b${i}\b" | wc -l) -ne 0; then
FILTERED_INCLUDES_LIST="${i} ${FILTERED_INCLUDES_LIST}"
fi
done
echo "${FILTERED_INCLUDES_LIST}"
}
# extract all header only files and headers and source files found in the external library required by specified library
# param ${1} name of the current library
# param ${2} name of the external dependency library required by current library
# return the list of header only files as 'HEADERS: heaser1.h header2.h' and header and source files as 'HEADERS_AND_SOURCES: source1.h source1.cc source2.h source2.cpp'
extract_non_include_files() {
# extract folder name for current library Makefile.am
CURRENT_FOLDER=$(extract_folder_name "src/lib/${1}/Makefile.am")"/"
# extract folder name for external dependency library Makefile.am
EXTERNAL_FOLDER=$(extract_folder_name "src/lib/${2}/Makefile.am")"/"
# select only files in current folder
SEARCH_FILES=$(echo "${FILE_LIST}" | grep "${CURRENT_FOLDER}")
HEADERS_LIST=
NON_HEADERS_LIST=
# select all lines containing '#include ' directive
RAW_INCLUDES_LIST=$(echo "${SEARCH_FILES}" | xargs grep "^#include " 2>/dev/null)
# filter only included headers found in other libraries by using the form 'other_lib_name/header_file.h'
# to do this it is required to select the string between '<' and '>', searching for '/' character, search for the extension marker '.' and returning the name after last '/'
RAW_INCLUDES_LIST=$(echo "${RAW_INCLUDES_LIST}" | cut -d "#" -f 2 | tr "\"" " " | cut -d "<" -f 2 | cut -d ">" -f 1 | grep "\/" | grep "\b${2}\b" | cut -d "/" -f 2 | grep "\." | sort | uniq)
# select only files in dependency library folder and strip full path
RELATIVE_SEARCH_FILES=$(echo "${FILE_LIST}" | grep "${EXTERNAL_FOLDER}" | sed -e "s#${REPO_FOLDER}${EXTERNAL_FOLDER}##g")
# search for the header file but also for source files
for i in ${RAW_INCLUDES_LIST}; do
# filter by name only (no extension)
FILTER=$(echo "${i}" | cut -d "." -f 1)
# filter non header files with exact name of the header file without the extension
NON_HEADER=$(echo "${RELATIVE_SEARCH_FILES}" | grep "\b${FILTER}\." | grep -v "${i}")
if test $(echo "${NON_HEADER}" | wc -w) -ne 0; then
# append header and source file names
NON_HEADERS_LIST="${i} ${NON_HEADER} ${NON_HEADERS_LIST}"
else
# append header only file name
HEADERS_LIST="${i} ${HEADERS_LIST}"
fi
done
# sort header only files
HEADERS_LIST=$(echo ${HEADERS_LIST} | tr -s " " | sort | uniq)
# sort header and source files
NON_HEADERS_LIST=$(echo ${NON_HEADERS_LIST} | tr -s " " | sort | uniq)
echo "HEADERS_AND_SOURCES:${NON_HEADERS_LIST}"
echo "HEADERS:${HEADERS_LIST}"
}
# extract all valid dependencies of a specified library
#
# param ${1} list of all libraries in the reverse compilation order
# param ${2} library name for which the dependency list is computed
# return the list of dependencies for specified library in the reverse compilation order
extract_dependencies() {
echo "${1}" | grep -Eo "\b${2}\b.*$"
}
# extract computed dependency for specified library
#
# param ${1} library name for which the dependency list is retrieved
# param ${2} library path for which the dependency list is retrieved
# return stored value of computed dependencies or 'NONE' if dependencies have not been computed yet
extract_computed_dependencies() {
PATH_TO_NAME=$(echo "${2}" | tr -s "/" "_")
NAME="COMPUTED_DEPENDENCIES_${PATH_TO_NAME}_${1}"
if test -n "${!NAME+x}"; then
echo "${!NAME}"
else
echo "NONE"
fi
}
# extract library directive
#
# param ${1} artifact path
extract_library_directive() {
ARTIFACT_PATH="${1}"
echo `cat ${ARTIFACT_PATH}/Makefile.am | grep "LIBADD\|LDADD" | sort | tr -s ' ' | cut -d " " -f 1 | sort -u`
}
# extract library name
#
# param ${1} artifact path
extract_library_name() {
ARTIFACT_PATH="${1}"
echo `cat ${ARTIFACT_PATH}/Makefile.am | grep "LIBRARIES" | tr -s ' ' | cut -d " " -f 3`
}
# compute artifact dependencies
#
# param ${1} artifact name
# param ${2} artifact path
compute_dependencies() {
ARTIFACT="${1}"
ARTIFACT_PATH="${2}"
echo ""
echo "########################################"
echo "### ${ARTIFACT_PATH}/${ARTIFACT}"
echo "########################################"
echo ""
# all valid dependencies that can be added by each dependency library
echo "${ARTIFACT_PATH}/${ARTIFACT} valid dependencies:"
echo "${VALID_LIST}"
# detect dependencies errors by searching for dependencies that are compiled after the current library and can generate missing symbols
NON_RECURSIVE_BASE_DEPENDENCIES=
for j in ${BASE_DEPENDENCIES}; do
# only add the dependency if it is in the valid dependencies list to prevent infinite recursion and log the error otherwise
if test $(echo "${VALID_LIST}" | grep "\b${j}\b" | wc -l) -eq 0; then
# search for external header and source files
INVALID_EXTERNAL_DEPENDENCIES=$(extract_non_include_files "${ARTIFACT}" "${j}")
# filter header only external files
EXTERNAL_HEADERS=$(echo "${INVALID_EXTERNAL_DEPENDENCIES}" | grep "HEADERS:" | cut -d ":" -f 2)
# filter header and source external files
EXTERNAL_ALL=$(echo "${INVALID_EXTERNAL_DEPENDENCIES}" | grep "HEADERS_AND_SOURCES:" | cut -d ":" -f 2)
echo "### ERROR ### dependencies ERROR for ${ARTIFACT_PATH}/${ARTIFACT} on ${j} with:"
# if there are any header only external files
if test $(echo "${EXTERNAL_ALL}" | wc -w) -ne 0; then
echo "non header only files: ${EXTERNAL_ALL}"
fi
# if there are any header and source external files
if test $(echo "${EXTERNAL_HEADERS}" | wc -w) -ne 0; then
echo "header only files: ${EXTERNAL_HEADERS}"
fi
else
# don't add current library to it's dependencies list
if test ${j} != ${ARTIFACT}; then
NON_RECURSIVE_BASE_DEPENDENCIES="${NON_RECURSIVE_BASE_DEPENDENCIES} ${j}"
fi
fi
done
# all found dependencies in the reverse compilation order
BASE_DEPENDENCIES=$(echo "${BASE_DEPENDENCIES}" | xargs)
# all found and valid dependencies in the reverse compilation order
NON_RECURSIVE_BASE_DEPENDENCIES=$(echo "${NON_RECURSIVE_BASE_DEPENDENCIES}" | xargs)
echo "${ARTIFACT_PATH}/${ARTIFACT} base dependencies:"
echo "${BASE_DEPENDENCIES}"
echo "${ARTIFACT_PATH}/${ARTIFACT} non recursive dependencies:"
echo "${NON_RECURSIVE_BASE_DEPENDENCIES}"
# minimum set of dependencies for current library
DEPENDENCIES=
for j in ${NON_RECURSIVE_BASE_DEPENDENCIES}; do
NEW_DEPENDENCIES=$(extract_computed_dependencies "${j}" "src/lib")
if test "${NEW_DEPENDENCIES}" == "NONE"; then
echo "### ERROR ### computed dependency not found for ${j}"
else
DEPENDENCIES="${NEW_DEPENDENCIES} ${DEPENDENCIES}"
fi
done
DEPENDENCIES=$(echo "${DEPENDENCIES} ${NON_RECURSIVE_BASE_DEPENDENCIES}" | tr -s " " "\n" | sort | uniq | xargs)
# order dependencies in the order of compilation
SORTED_DEPENDENCIES=
for j in ${LIBRARIES_LIST}; do
if test $(echo "${DEPENDENCIES}" | grep "\b${j}\b" | wc -l) -ne 0; then
SORTED_DEPENDENCIES="${j} ${SORTED_DEPENDENCIES}"
fi
done
echo "${ARTIFACT_PATH}/${ARTIFACT} minimum dependencies:"
echo "${SORTED_DEPENDENCIES}"
echo ""
echo "++++++++++++++++++++++++++++++++++++++++"
ARTIFACT_DIRECTIVE=$(extract_library_directive ${ARTIFACT_PATH}/${ARTIFACT})
for j in ${SORTED_DEPENDENCIES}; do
DEPENDENCY_LIBRARY_NAME=$(extract_library_name "src/lib/${j}")
echo "${ARTIFACT_DIRECTIVE} += \$(top_builddir)/src/lib/${j}/${DEPENDENCY_LIBRARY_NAME}"
done
echo "++++++++++++++++++++++++++++++++++++++++"
echo "########################################"
echo ""
}
# if wrong number of parameters print usage
if test ${#} -ne 1; then
echo "Usage: ${0} path/to/kea/repo"
exit
fi
# folder containing full repo
REPO_FOLDER=${1}
if test $(echo -n ${REPO_FOLDER} | tail -c 1) != "/"; then
REPO_FOLDER="${REPO_FOLDER}/"
fi
# filter all Makefile.am files
MAKEFILES_LIST=$(find ${REPO_FOLDER} | grep "Makefile\.am" | sed -e "s#${REPO_FOLDER}##g" | grep "src\/" | sort)
# if no Makefile.am found exit
if test -z "${MAKEFILES_LIST}"; then
echo "invalid repo path: no Makefile.am file found"
exit
fi
echo "list of Makefile.am:"
echo "${MAKEFILES_LIST}"
# base Makefile.am for all sources is in src/lib/Makefile.am
BASE_MAKEFILE=$(echo "${MAKEFILES_LIST}" | grep "src\/lib\/Makefile.am")
# if no src/lib/Makefile.am found exit
if test -z ${BASE_MAKEFILE}; then
echo "invalid repo path: no src/lib/Makefile.am file found"
exit
fi
echo "base Makefile.am:"
echo "${BASE_MAKEFILE}"
# generate the list of libraries in the compilation order
LIBRARIES_LIST=
RAW_LIBRARIES_LIST=$(cat "${REPO_FOLDER}${BASE_MAKEFILE}" | grep "SUBDIRS")
for i in ${RAW_LIBRARIES_LIST}; do
LIBRARIES_LIST="${LIBRARIES_LIST} $(echo ${i} | grep -v "SUBDIRS" | grep -v '=')"
done
# remove empty spaces
LIBRARIES_LIST=$(echo "${LIBRARIES_LIST}" | tr -s ' ' | xargs)
# generate the list of libraries in the reverse compilation order
REVERSE_LIBRARIES_LIST=
for i in ${LIBRARIES_LIST}; do
REVERSE_LIBRARIES_LIST="${i} ${REVERSE_LIBRARIES_LIST}"
done
echo "list of libraries:"
echo "${LIBRARIES_LIST}"
echo "reverse list of libraries:"
echo "${REVERSE_LIBRARIES_LIST}"
# filter all files of interest ignoring irrelevant ones
# ignore .git, .libs, .deps doc folders and .o .lo .Plo .Po .gcno .gcda .m4 .dox .json .mes files
FILE_LIST=$(find "${REPO_FOLDER}" 2>/dev/null | grep -v "\.git" | grep -v "\/\.libs\/" | grep -v "\.o$" | grep -v "\/\.deps\/" | grep -v "\.lo$" | grep -v "\.Plo$" | grep -v "\.Po$" | grep -v "\.gcno$" | grep -v "gcda" | grep -v "\.m4$" | grep -v "\.dox$" | grep -v "\.json$" | grep -v "\/doc\/" | grep -v "\.mes$" | sort)
#echo "files:"
#echo "${FILE_LIST}"
BASE_LIBRARIES_MAKEFILES=
# generate the list of dependencies for all libraries in src/lib
for i in ${LIBRARIES_LIST}; do
# generate current library Makefile.am path
BASE_LIBRARIES_MAKEFILES="${BASE_LIBRARIES_MAKEFILES} src/lib/${i}/Makefile.am"
# extract dependencies found in the library folder
BASE_DEPENDENCIES=$(extract_includes "src/lib/${i}/Makefile.am")
# generate the list of valid dependencies for the current library (take compilation order into account)
VALID_LIST=$(extract_dependencies "${REVERSE_LIBRARIES_LIST}" "${i}")
compute_dependencies "${i}" "src/lib"
PATH_TO_NAME=$(echo "src/lib" | tr -s "/" "_")
declare COMPUTED_DEPENDENCIES_${PATH_TO_NAME}_${i}="${SORTED_DEPENDENCIES}"
done
# remove empty spaces
BASE_LIBRARIES_MAKEFILES=$(echo "${BASE_LIBRARIES_MAKEFILES}" | xargs | tr -s " " "\n")
echo "base Makefiles.am files:"
echo "${BASE_LIBRARIES_MAKEFILES}"
OTHER_MAKEFILES=$(echo "${MAKEFILES_LIST}" | tr -s " " "\n" | grep -v "src/lib/" | grep -v "src/share/" | grep -v "src/Makefile.am")
# remove empty spaces
OTHER_MAKEFILES=$(echo "${OTHER_MAKEFILES}" | xargs | tr -s " " "\n")
echo "remaining Makefile.am files:"
echo "${OTHER_MAKEFILES}"
for i in ${OTHER_MAKEFILES}; do
# extract dependencies found in the artifact folder
BASE_DEPENDENCIES=$(extract_includes "${i}")
# generate the list of valid dependencies for the current artifact (take compilation order into account)
VALID_LIST="${REVERSE_LIBRARIES_LIST}"
ARTIFACT=$(echo "${i}" | rev | cut -d "/" -f 2 | rev)
ARTIFACT_PATH=$(echo "${i}" | rev | cut -d "/" -f 3- | rev)
compute_dependencies "${ARTIFACT}" "${ARTIFACT_PATH}"
PATH_TO_NAME=$(echo "${ARTIFACT_PATH}" | tr -s "/" "_")
declare COMPUTED_DEPENDENCIES_${PATH_TO_NAME}_${ARTIFACT}="${SORTED_DEPENDENCIES}"
done
exit
|