2024-06-17 17:07:22 +03:00
#!/bin/sh
2024-03-27 23:38:26 +02:00
2024-06-17 17:07:22 +03:00
set -eu
script_path = $( cd " $( dirname " ${ 0 } " ) " && pwd )
top_srcdir = $( realpath " ${ script_path } /.. " )
2024-03-27 23:38:26 +02:00
# 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( ) {
2024-06-17 17:07:22 +03:00
# extract folder name from current library Makefile.am
CURRENT_FOLDER = $( dirname " ${ 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 -u)
# 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 -c " \b ${ i } \b " ) " -ne 0; then
FILTERED_INCLUDES_LIST = " ${ i } ${ FILTERED_INCLUDES_LIST } "
fi
done
echo " ${ FILTERED_INCLUDES_LIST } "
2024-03-27 23:38:26 +02:00
}
# 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( ) {
2024-06-17 17:07:22 +03:00
# extract folder name for current library Makefile.am
CURRENT_FOLDER = $( dirname " src/lib/ ${ 1 } /Makefile.am " ) "/"
# extract folder name for external dependency library Makefile.am
EXTERNAL_FOLDER = $( dirname " 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 -u)
# select only files in dependency library folder and strip full path
RELATIVE_SEARCH_FILES = $( echo " ${ FILE_LIST } " | grep " ${ EXTERNAL_FOLDER } " | sed -e " s# ${ 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 -u)
# sort header and source files
NON_HEADERS_LIST = $( echo " ${ NON_HEADERS_LIST } " | tr -s " " | sort -u)
echo " HEADERS_AND_SOURCES: ${ NON_HEADERS_LIST } "
echo " HEADERS: ${ HEADERS_LIST } "
2024-03-27 23:38:26 +02:00
}
# 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
2024-06-17 17:07:22 +03:00
# return the list of dependencies for specified library in the reverse compilation order
2024-03-27 23:38:26 +02:00
extract_dependencies( ) {
2024-06-17 17:07:22 +03:00
echo " ${ 1 } " | grep -Eo " \b ${ 2 } \b.* $"
2024-03-27 23:38:26 +02:00
}
# 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( ) {
2024-06-17 17:07:22 +03:00
PATH_TO_NAME = $( echo " ${ 2 } " | tr -s "/" "_" )
NAME = " COMPUTED_DEPENDENCIES_ ${ PATH_TO_NAME } _ ${ 1 } "
if test -n " $( eval " echo \"\${ $NAME +x}\" " ) " ; then
eval " echo \"\${ $NAME }\" "
else
echo "NONE"
fi
2024-03-27 23:38:26 +02:00
}
# extract library directive
#
# param ${1} artifact path
extract_library_directive( ) {
2024-06-17 17:07:22 +03:00
ARTIFACT_PATH = " ${ 1 } "
grep 'LIBADD\|LDADD' " ${ ARTIFACT_PATH } /Makefile.am " | sort | tr -s ' ' | cut -d " " -f 1 | sort -u | tr '\n' ' ' | sed 's/ *$//'
2024-03-27 23:38:26 +02:00
}
# extract library name
#
# param ${1} artifact path
extract_library_name( ) {
2024-06-17 17:07:22 +03:00
ARTIFACT_PATH = " ${ 1 } "
grep 'LIBRARIES' " ${ ARTIFACT_PATH } /Makefile.am " | grep "LIBRARIES" | tr -s ' ' | cut -d " " -f 3
2024-03-27 23:38:26 +02:00
}
# compute artifact dependencies
#
# param ${1} artifact name
# param ${2} artifact path
compute_dependencies( ) {
2024-06-17 17:07:22 +03:00
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 -c " \b ${ j } \b " ) " -eq 0; then
# search for external header and source files
INVALID_EXTERNAL_DEPENDENCIES = $( extract_non_include_files " ${ ARTIFACT } " " ${ j } " ) || true
# 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
2024-06-20 17:19:03 +03:00
BASE_DEPENDENCIES = $( echo " ${ BASE_DEPENDENCIES } " | sed 's/ *$//' )
2024-06-17 17:07:22 +03:00
# all found and valid dependencies in the reverse compilation order
2024-06-20 17:19:03 +03:00
NON_RECURSIVE_BASE_DEPENDENCIES = $( echo " ${ NON_RECURSIVE_BASE_DEPENDENCIES } " | sed 's/^ *//;s/ *$//' )
2024-06-17 17:07:22 +03:00
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
2024-06-20 17:19:03 +03:00
DEPENDENCIES = $( echo " ${ DEPENDENCIES } ${ NON_RECURSIVE_BASE_DEPENDENCIES } " | tr -s " " "\n" | sort -u | sed 's/ *$//' )
2024-06-17 17:07:22 +03:00
# order dependencies in the order of compilation
SORTED_DEPENDENCIES =
for j in ${ LIBRARIES_LIST } ; do
if test " $( echo " ${ DEPENDENCIES } " | grep -c " \b ${ j } \b " ) " -ne 0; then
SORTED_DEPENDENCIES = " ${ j } ${ SORTED_DEPENDENCIES } "
fi
done
SORTED_DEPENDENCIES = $( echo " ${ SORTED_DEPENDENCIES } " | sed 's/ *$//g' )
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 ""
2024-03-27 23:38:26 +02:00
}
2024-06-17 17:07:22 +03:00
# Folder containing full repo. Default is "tools/.."
REPO_FOLDER = " ${ 1 - ${ top_srcdir } } "
cd " ${ REPO_FOLDER } "
2024-03-27 23:38:26 +02:00
# filter all Makefile.am files
2024-06-17 17:07:22 +03:00
MAKEFILES_LIST = $( find . -type f -wholename '*src/*Makefile.am' | sed 's#\./##g' | sort)
2024-03-27 23:38:26 +02:00
# if no Makefile.am found exit
if test -z " ${ MAKEFILES_LIST } " ; then
2024-06-17 17:07:22 +03:00
echo "invalid repo path: no Makefile.am file found"
exit
2024-03-27 23:38:26 +02:00
fi
echo "list of Makefile.am:"
echo " ${ MAKEFILES_LIST } "
# base Makefile.am for all sources is in src/lib/Makefile.am
2024-06-17 17:07:22 +03:00
BASE_MAKEFILE = $( echo " ${ MAKEFILES_LIST } " | grep "src/lib/Makefile.am" )
2024-03-27 23:38:26 +02:00
# if no src/lib/Makefile.am found exit
2024-06-17 17:07:22 +03:00
if test -z " ${ BASE_MAKEFILE } " ; then
echo "invalid repo path: no src/lib/Makefile.am file found"
exit
2024-03-27 23:38:26 +02:00
fi
echo "base Makefile.am:"
echo " ${ BASE_MAKEFILE } "
# generate the list of libraries in the compilation order
LIBRARIES_LIST =
2024-06-17 17:07:22 +03:00
RAW_LIBRARIES_LIST = $( grep 'SUBDIRS' " ${ BASE_MAKEFILE } " )
LIBRARIES_LIST = $( echo " ${ RAW_LIBRARIES_LIST } " | tr ' ' '\n' | grep -v SUBDIRS | grep -v '=' | tr '\n' ' ' | sed 's/ *$//' )
2024-03-27 23:38:26 +02:00
# generate the list of libraries in the reverse compilation order
2024-06-17 17:07:22 +03:00
REVERSE_LIBRARIES_LIST = $( echo " ${ LIBRARIES_LIST } " | tr ' ' '\n' | tac | tr '\n' ' ' | sed 's/ *$//' )
2024-03-27 23:38:26 +02:00
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
2024-06-17 17:07:22 +03:00
FILE_LIST = $( find . 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)
2024-03-27 23:38:26 +02:00
#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
2024-06-17 17:07:22 +03:00
# 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 " ) || true
# 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 "/" "_" )
export " COMPUTED_DEPENDENCIES_ ${ PATH_TO_NAME } _ ${ i } = ${ SORTED_DEPENDENCIES } "
2024-03-27 23:38:26 +02:00
done
# remove empty spaces
2024-06-17 17:07:22 +03:00
BASE_LIBRARIES_MAKEFILES = $( echo " ${ BASE_LIBRARIES_MAKEFILES } " | sed 's/ *$//' | tr ' ' '\n' )
2024-03-27 23:38:26 +02:00
2024-06-17 17:07:22 +03:00
echo "base Makefile.am files:"
2024-03-27 23:38:26 +02:00
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" )
echo "remaining Makefile.am files:"
echo " ${ OTHER_MAKEFILES } "
for i in ${ OTHER_MAKEFILES } ; do
2024-06-17 17:07:22 +03:00
# extract dependencies found in the artifact folder
BASE_DEPENDENCIES = $( extract_includes " ${ i } " ) || true
# 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 "/" "_" )
export " COMPUTED_DEPENDENCIES_ ${ PATH_TO_NAME } _ ${ ARTIFACT } = ${ SORTED_DEPENDENCIES } "
2024-03-27 23:38:26 +02:00
done