mirror of
https://github.com/gryf/wmaker.git
synced 2025-12-19 12:28:22 +01:00
As reported by Andreas Metzler, the latest API change in lib WRaster caused a compatibility issue because the internal version number was increased. To correctly handle this situation, this patch does 2 things: - do not discard the 2 last number in the "c:r:a" version, because we need them; - when calculating the version for the mapfile, use the formula that is suggested in libtool's documentation. The purpose of the formula is that when API is changed, if a new function is added then the version is not incremented to reflect that we are still compatible with current binaries, it will be incremented only when there is a break in compatibility.
249 lines
7.6 KiB
Bash
Executable File
249 lines
7.6 KiB
Bash
Executable File
#!/bin/sh
|
|
###########################################################################
|
|
#
|
|
# Window Maker window manager
|
|
#
|
|
# Copyright (c) 2014 Christophe CURIS
|
|
# Copyright (c) 2014-2015 Window Maker Team
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License along
|
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
#
|
|
###########################################################################
|
|
#
|
|
# generate-mapfile-from-header.sh:
|
|
# from a list of C header files, extract the name of the functions and
|
|
# global variables that are considered public for a library, and generate
|
|
# a 'version script' for ld with that list, so that all other symbols
|
|
# will be considered local.
|
|
#
|
|
# The goal is that the symbol that are not part of the public API should
|
|
# not be visible to the user because it can be a source of problems (from
|
|
# name clash to evolutivity issues).
|
|
#
|
|
###########################################################################
|
|
#
|
|
# Please note that this script is writen in sh+awk on purpose: this script
|
|
# is gonna be run on the machine of the person who is trying to compile
|
|
# WindowMaker, and as such we cannot be sure to find any scripting language
|
|
# in a known version and that works (python/ruby/tcl/perl/php/you-name-it).
|
|
#
|
|
# So for portability, we stick to the same sh+awk constraint as Autotools
|
|
# to limit the problem, see for example:
|
|
# http://www.gnu.org/savannah-checkouts/gnu/autoconf/manual/autoconf-2.69/html_node/Portable-Shell.html
|
|
#
|
|
###########################################################################
|
|
|
|
# Report an error on stderr and exit with status 1 to tell make could not work
|
|
arg_error() {
|
|
echo "$0: $@" >&2
|
|
exit 1
|
|
}
|
|
|
|
# print help and exit with success status
|
|
print_help() {
|
|
echo "$0: generate a script for ld to keep only the symbols from C header"
|
|
echo "Usage: $0 [options...] input_file[s]"
|
|
echo "valid options are:"
|
|
echo " -l : add symbol's definition line number for debug"
|
|
echo " -n name : name to use for the library"
|
|
echo " -v version : set the library version for ld"
|
|
exit 0
|
|
}
|
|
|
|
# Extract command line arguments
|
|
while [ $# -gt 0 ]; do
|
|
case $1 in
|
|
-l)
|
|
debug_info=' /* " symbol_type " at " FILENAME ":" NR " */'
|
|
;;
|
|
|
|
-n)
|
|
shift
|
|
echo "$1" | grep '^[A-Za-z][A-Za-z_0-9]*$' > /dev/null || arg_error "invalid name \"$1\" for a library"
|
|
libname="$1"
|
|
;;
|
|
|
|
-v)
|
|
shift
|
|
version="$1"
|
|
echo "$version" | grep -E '^[1-9][0-9]*(:[0-9]+(:[0-9]+)?)?$' > /dev/null || \
|
|
arg_error "version \"$1\" is not valid"
|
|
;;
|
|
|
|
-h|-help|--help) print_help ;;
|
|
-*) arg_error "unknow option '$1'" ;;
|
|
|
|
*)
|
|
[ -r "$1" ] || arg_error "source file \"$1\" is not readable"
|
|
input_files="$input_files $1"
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
# Check consistency of command-line
|
|
[ "x$input_files" = "x" ] && arg_error "no source file given"
|
|
|
|
# Automatic values
|
|
if [ -z "$libname" ]; then
|
|
# build the library name from the first header name, remove path stuff, extension and invalid characters
|
|
libname="`echo "$input_files" | sed -e 's,^ ,,;s, .*$,,;s,^.*/\([^/]*\)$,\1,;s,\.[^.]*$,,;s,[^A-Za-z_0-9],_,g;s,^_*,,' `"
|
|
fi
|
|
|
|
# Parse the input file and find the function declarations; extract the names
|
|
# and place them in the 'global' section so that ld will keep the symbols;
|
|
# generate the rest of the script so that other symbols will not be kept.
|
|
awk '
|
|
BEGIN {
|
|
# Version number here uses only 1 number from the full version used in libtool
|
|
libversion="'"$version"'";
|
|
if (split(libversion, subversions, ":") > 1) {
|
|
# Calculate [CURRENT - AGE], the goal is that the number will not
|
|
# change when functions are added to the API, but it will be incremented
|
|
# when functions are removed or argument change (which breaks compat)
|
|
libversion = subversions[1] - subversions[3];
|
|
}
|
|
|
|
print "/* Generated version-script for ld */";
|
|
print "";
|
|
print "'"$libname"'" libversion;
|
|
print "{";
|
|
print " global:";
|
|
}
|
|
|
|
/^#[ \t]*define/ {
|
|
# Ignore macro definition because their content could be mis-interpreted
|
|
while (/\\$/) {
|
|
if (getline == 0) { break; }
|
|
}
|
|
next;
|
|
}
|
|
|
|
/\/\*/ {
|
|
# Remove comments to avoid mis-detection
|
|
pos = index($0, "/*");
|
|
comment = substr($0, pos + 2);
|
|
$0 = substr($0, 1, pos - 1);
|
|
while (1) {
|
|
pos = index(comment, "*/");
|
|
if (pos > 0) { break; }
|
|
getline comment;
|
|
}
|
|
$0 = $0 substr(comment, pos + 2);
|
|
}
|
|
|
|
/extern[ \t].*;/ {
|
|
line = $0;
|
|
|
|
# Remove everything from the ";"
|
|
sub(/;.*$/, "", line);
|
|
|
|
# Check if it is a global variable
|
|
nb = split(line, words, /[\t *]/);
|
|
|
|
valid = 1;
|
|
for (i = 1; i < nb; i++) {
|
|
# If the word looks valid, do not abort
|
|
if (words[i] ~ /^[A-Za-z_0-9]*$/) { continue; }
|
|
|
|
# Treat the case were the variable is an array, and there was space(s) after the name
|
|
if (words[i] ~ /^\[/) { nb = i - 1; break; }
|
|
|
|
# If we are here, the word is not valid; we stop processing the line here but we do
|
|
# not use "next" so the line may match function prototype handler below
|
|
valid = 0;
|
|
break;
|
|
}
|
|
|
|
if (valid) {
|
|
# Remove array size, if any
|
|
sub(/\[.*$/, "", words[nb]);
|
|
|
|
if (words[nb] ~ /^[A-Za-z][A-Za-z_0-9]*$/) {
|
|
symbol_type = "variable";
|
|
print " " words[nb] ";'"$debug_info"'";
|
|
next;
|
|
}
|
|
}
|
|
}
|
|
|
|
/^[ \t]*typedef/ {
|
|
# Skip type definition because they could be mis-interpreted when it
|
|
# defines a prototype for a callback function
|
|
nb_braces = 0;
|
|
while (1) {
|
|
# Count the number of brace pairs to skip the content of the definition
|
|
nb = split($0, dummy_array, /\{/);
|
|
nb_braces = nb_braces + nb;
|
|
|
|
nb = split($0, dummy_array, /\}/);
|
|
nb_braces = nb_braces - nb;
|
|
|
|
# Stop when we have out count of pair of braces and there is the final ";"
|
|
if ((nb_braces == 0) && (dummy_array[nb] ~ /;/)) { break; }
|
|
|
|
if (getline == 0) {
|
|
break;
|
|
}
|
|
}
|
|
next;
|
|
}
|
|
|
|
/[\t ]\**[A-Z_a-z][A-Z_a-z0-9]*[\t ]*\(/ {
|
|
# Get everything until the end of the definition, to avoid mis-interpreting
|
|
# arguments and attributes on next lines
|
|
while (1) {
|
|
pos = index($0, ";");
|
|
if (pos != 0) { break; }
|
|
|
|
getline nxt;
|
|
$0 = $0 nxt;
|
|
}
|
|
|
|
# Remove the argument list
|
|
sub(/[ \t]*\(.*$/, "");
|
|
|
|
# Trim possible indentation at beginning of line
|
|
sub(/^[\t ]*/, "");
|
|
|
|
# If it does not start by a keyword, it is probably not a valid function
|
|
if (!/^[A-Z_a-z]/) { next; }
|
|
|
|
nb = split($0, words, /[\t *]/);
|
|
for (i = 1; i < nb; i++) {
|
|
# Do not consider "static" because it is used for functions to be inlined
|
|
if (words[i] == "static") { next; }
|
|
|
|
# Allow empty keyword, that were just "*"
|
|
if (words[i] == "") { continue; }
|
|
|
|
# If it does not match, it is unlikely to be a function
|
|
if (words[i] !~ /^[A-Z_a-z][A-Z_a-z0-9]*$/) { next; }
|
|
}
|
|
|
|
# If we arrived so far, everything looks valid and the last argument of
|
|
# the array contains the name of the function
|
|
symbol_type = "function";
|
|
print " " words[nb] ";'"$debug_info"'";
|
|
}
|
|
|
|
END {
|
|
print "";
|
|
print " local:";
|
|
print " *;";
|
|
print "};";
|
|
}
|
|
' $input_files
|