summaryrefslogtreecommitdiff
path: root/build
diff options
context:
space:
mode:
authorTristan Van Berkom <tristan@upstairslabs.com>2013-12-16 18:36:18 +0900
committerTristan Van Berkom <tristan@upstairslabs.com>2013-12-16 18:36:18 +0900
commit93ddfbc90c12ee5672552712b686bf8d09bce088 (patch)
tree3b173a15c727a9045e5cb3e067224279210ba9fb /build
parenta56b095832be4589975b1192ab445fda5705038b (diff)
downloadglade-93ddfbc90c12ee5672552712b686bf8d09bce088.tar.gz
Greatly improved the LibcWrapGenerator.vala program.
Diffstat (limited to 'build')
-rw-r--r--build/linux/LibcWrapGenerator.vala412
1 files changed, 207 insertions, 205 deletions
diff --git a/build/linux/LibcWrapGenerator.vala b/build/linux/LibcWrapGenerator.vala
index c8aa5aff..a6a61752 100644
--- a/build/linux/LibcWrapGenerator.vala
+++ b/build/linux/LibcWrapGenerator.vala
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2011 Jan Niklas Hasse <jhasse@gmail.com>
- * Copyright (C) 2013 Tristan Van Berkom <tristan@upstairslabs.com>
+ * Copyright (C) 2013 Upstairs Laboratories Inc.
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
@@ -19,37 +19,12 @@
* Authors:
* Jan Niklas Hasse <jhasse@gmail.com>
* Tristan Van Berkom <tristan@upstairslabs.com>
- *
- *
- * This program is used to generate a header safely selecting the ABI
- * glibc requirement.
- *
- * The resulting program can be run as such:
- *
- * ./LibcWrapGenerator libcwrap.h 2.7 /path/to/libc/runtime/libraries
- *
- * This will generate a libcwrap.h which should be included by any
- * C/C++ sources before anything else, redirecting any references
- * to glibc symbols > 2.7 to symbols from previous versions.
- *
- * For symbols which are found to be new after 2.7, those will be
- * redirected to symbol@GLIBC_DONT_USE_THIS_SYMBOL_2.10 (or whichever
- * version the said symbol was actually added in)
- *
- * This will generate a link error at compile time, it is possible
- * however unlikely that these link errors will occur, if they do
- * you must patch the sources in such a way that those glibc symbols
- * which generated the link error are not accessed.
- *
- * Sources should also be compiled with -U_FORTIFY_SOURCE as some
- * compilers build in _FORTIFY_SOURCE by default, enabling some
- * glibc runtime checkers to be linked into your source code.
- *
- * We recommend disabling _FORTIFY_SOURCE since most of the runtime
- * checkers are only available in relatively recent versions of glibc.
*/
using GLib;
+static const string DEFAULT_TARGET = "2.7";
+static const string DEFAULT_TARGET_HELP = "Target glibc ABI (Default 2.7)";
+
/***************************************************************
* Debugging Facilities *
***************************************************************/
@@ -91,146 +66,209 @@ class VersionNumber : Object
private int revision { get; set; } // 0.0.x
private string originalString;
- public VersionNumber(string version)
- {
+ public VersionNumber (string version) {
+
originalString = version;
- try
- {
+
+ try {
var regex = new Regex("([[:digit:]]*)\\.([[:digit:]]*)\\.*([[:digit:]]*)");
var split = regex.split(version);
- assert(split.length > 1); // TODO: Don't use assert, print a nice error message instead
+
+ assert (split.length > 1); // TODO: Don't use assert, print a nice error message instead
major = int.parse (split[1]);
- if(split.length > 2)
- {
+
+ if (split.length > 2)
minor = int.parse (split[2]);
- }
else
- {
minor = 0;
- }
- if(split.length > 3)
- {
+
+ if (split.length > 3)
revision = int.parse (split[3]);
- }
else
- {
revision = 0;
- }
- }
- catch(GLib.RegexError e)
- {
+ } catch (GLib.RegexError e) {
stdout.printf("Error compiling regular expression!");
Posix.exit(-1);
}
}
-
- public bool newerThan(VersionNumber other)
- {
- if(major > other.major)
- {
+
+ public bool newerThan(VersionNumber other) {
+
+ if (major > other.major) {
return true;
- }
- else if(major == other.major)
- {
- if(minor > other.minor)
- {
+ } else if (major == other.major) {
+
+ if (minor > other.minor) {
return true;
- }
- else if(minor == other.minor)
- {
- if(revision > other.revision)
- {
+ } else if (minor == other.minor) {
+
+ if(revision > other.revision) {
return true;
}
}
}
+
return false;
}
- public string getString()
- {
+
+ public string getString() {
return originalString;
}
}
/***************************************************************
- * Symbol output *
+ * Main *
***************************************************************/
-private void
-append_symbols (StringBuilder headerFile,
- VersionNumber minimumVersion,
- Gee.HashMap<string, VersionNumber> symbolMap,
- Gee.HashSet<string>filterMap,
- bool overrides)
-{
+public class Main : Object {
+
+ /* Command line options */
+ private static string? libdir = null;
+ private static string? output = null;
+ private static string? target = null;
+
+ private const GLib.OptionEntry[] options = {
+ { "libdir", 'l', 0, OptionArg.FILENAME, ref libdir, "Library directory", "<DIRECTORY>" },
+ { "output", 'o', 0, OptionArg.STRING, ref output, "Header to create", "<FILENAME>" },
+ { "target", 't', 0, OptionArg.STRING, ref target, DEFAULT_TARGET_HELP, "<MAJOR.MINOR[.MICRO]>" },
+ { null }
+ };
+
+ /* Local variables */
+ private static VersionNumber minimumVersion;
+ private static Gee.HashMap<string, VersionNumber>symbolMap;
+ private static Gee.HashSet<string>filterMap;
+ private static Regex regex;
+
+ public static int main (string[] args) {
+
+ try {
+ var opt_context = new OptionContext ("- Libc compatibility header generator");
+ opt_context.set_help_enabled (true);
+ opt_context.add_main_entries (options, null);
+ opt_context.parse (ref args);
+ } catch (OptionError e) {
+ stdout.printf ("error: %s\n", e.message);
+ stdout.printf ("Run '%s --help' for a list of available command line options.\n", args[0]);
+ return 0;
+ }
- if (overrides)
- headerFile.append("\n/* Symbols introduced in newer glibc versions, which must not be used */\n");
- else
- headerFile.append("\n/* Symbols redirected to earlier glibc versions */\n");
+ if (libdir == null) {
+ stdout.printf ("Must specify --libdir\n");
+ stdout.printf ("Run '%s --help' for a list of available command line options.\n", args[0]);
+ return 0;
+ }
- foreach (var it in symbolMap.keys)
- {
- var version = symbolMap.get (it);
- string versionToUse;
+ if (output == null) {
+ stdout.printf ("Must specify --output\n");
+ stdout.printf ("Run '%s --help' for a list of available command line options.\n", args[0]);
+ return 0;
+ }
- /* If the symbol only has occurrences older than the minimum required glibc version,
- * then there is no need to output anything for this symbol
- */
- if (filterMap.contains (it))
- continue;
+ if (target == null)
+ target = DEFAULT_TARGET;
- if (overrides && version.newerThan (minimumVersion))
- versionToUse = "DONT_USE_THIS_VERSION_%s".printf (version.getString());
- else if (!overrides && !version.newerThan (minimumVersion))
- versionToUse = version.getString ();
- else
- continue;
+ /* Initialize local resources */
+ minimumVersion = new VersionNumber (target);
- headerFile.append("__asm__(\".symver %s, %s@GLIBC_%s\");\n".printf(it, it, versionToUse));
- }
-}
+ /* All symbols, containing the newest possible version before 'minimumVersion' if possible */
+ symbolMap = new Gee.HashMap<string, VersionNumber>((Gee.HashDataFunc<string>)GLib.str_hash,
+ (Gee.EqualDataFunc<string>)GLib.str_equal);
-/***************************************************************
- * Main *
- ***************************************************************/
-int main(string[] args)
-{
- try
- {
- if(args.length != 4)
- {
- stdout.printf("Usage: buildlist <header file to create> <minimum glibc version> <system library directory>\n");
+ /* All symbols which did not have any version > minimumVersion */
+ filterMap = new Gee.HashSet<string>((Gee.HashDataFunc<string>)GLib.str_hash,
+ (Gee.EqualDataFunc<string>)GLib.str_equal);
+
+ try {
+
+ stdout.printf ("Generating %s (glibc %s) from libs at '%s' .", output, minimumVersion.getString(), libdir);
+
+ regex = new Regex("(.*)(GLIBC_)([0-9]+\\.([0-9]+\\.)*[0-9]+)(\\)?)([ ]*)(.+)");
+ parseLibraries ();
+ generateHeader ();
+
+ } catch (Error e) {
+
+ warning("%s", e.message);
return 1;
}
- var minimumVersion = new VersionNumber(args[2]);
- var filename = args[1];
- var syslibs = args[3];
+ stdout.printf(" OK\n");
- stdout.printf ("Generating %s (glibc %s) from libs at '%s' .", filename, minimumVersion.getString(), syslibs);
+ return 0;
+ }
- var headerFile = new StringBuilder ();
- headerFile.append ("/* glibc bindings for target ABI version glibc " + minimumVersion.getString() + " */\n");
- stdout.flush();
+ private static void parseLibrary (FileInfo fileinfo) throws Error {
string output, errorOutput;
int returnCode;
- var libPath = File.new_for_path (syslibs);
- var enumerator = libPath.enumerate_children (FileAttribute.STANDARD_NAME, 0, null);
- FileInfo fileinfo;
- var counter = 0;
- /* This map will contain every symbol with new version as close to the minimum version as possible
- * including symbols which have a higher version than the minimum
- */
- var symbolMap = new Gee.HashMap<string, VersionNumber>((Gee.HashDataFunc<string>)GLib.str_hash,
- (Gee.EqualDataFunc<string>)GLib.str_equal);
+ Process.spawn_command_line_sync ("objdump -T " + libdir + "/" + fileinfo.get_name(),
+ out output, out errorOutput, out returnCode);
- /* This map will contain only symbols for which a version newer than the minimum was not found,
- * these symbols are safe to exclude from the output
- */
- var symbolsOlderThanMinimum = new Gee.HashSet<string>((Gee.HashDataFunc<string>)GLib.str_hash,
- (Gee.EqualDataFunc<string>)GLib.str_equal);
+ if (returnCode != 0)
+ return;
+
+ foreach (var line in output.split ("\n")) {
+
+ if (regex.match (line) && !("PRIVATE" in line)) {
+ var version = new VersionNumber (regex.split (line)[3]);
+ var symbolName = regex.split (line)[7];
+ var versionInMap = symbolMap.get (symbolName);
+
+ /* Some versioning symbols exist in the objdump output, let's skip those */
+ if (symbolName.has_prefix ("GLIBC"))
+ continue;
+
+ libcwrap_note (DF.COLLECT, () =>
+ stdout.printf ("Selected symbol '%s' version '%s' from objdump line %s\n",
+ symbolName, version.getString(), line));
+
+ if (versionInMap == null) {
+
+ symbolMap.set (symbolName, version);
+
+ /* First occurance of the symbol, if it's older
+ * than the minimum required, put it in that table also
+ */
+ if (minimumVersion.newerThan (version)) {
+ filterMap.add (symbolName);
+ libcwrap_note (DF.FILTER, () =>
+ stdout.printf ("Adding symbol '%s %s' to the filter\n",
+ symbolName, version.getString()));
+ }
+
+ } else {
+
+ /* We want the newest possible version of a symbol which is older than the
+ * minimum glibc version specified (or the only version of the symbol if
+ * it's newer than the minimum version)
+ */
+ if (version.newerThan (versionInMap) && minimumVersion.newerThan (version))
+ symbolMap.set (symbolName, version);
+
+ /* While trucking along through the huge symbol list, remove symbols from
+ * the 'safe to exclude' if there is a version found which is newer
+ * than the minimum requirement
+ */
+ if (version.newerThan (minimumVersion)) {
+ filterMap.remove(symbolName);
+ libcwrap_note (DF.FILTER, () =>
+ stdout.printf ("Removing symbol '%s %s' from the filter\n",
+ symbolName, version.getString()));
+ }
+ }
+
+ } else {
+ libcwrap_note (DF.COLLECT, () => stdout.printf ("Rejected objdump line %s\n", line));
+ }
+ }
+ }
+
+ private static void parseLibraries () throws Error {
+ var libPath = File.new_for_path (libdir);
+ var enumerator = libPath.enumerate_children (FileAttribute.STANDARD_NAME, 0, null);
+ var counter = 0;
+ FileInfo fileinfo;
while ((fileinfo = enumerator.next_file(null)) != null)
{
@@ -240,76 +278,52 @@ int main(string[] args)
stdout.flush();
}
- Process.spawn_command_line_sync("objdump -T " + syslibs + "/" + fileinfo.get_name(),
- out output, out errorOutput, out returnCode);
+ parseLibrary (fileinfo);
+ }
+ }
+
+ private static void appendSymbols (StringBuilder headerFile, bool overrides) {
- if (returnCode != 0)
+ if (overrides)
+ headerFile.append("\n/* Symbols introduced in newer glibc versions, which must not be used */\n");
+ else
+ headerFile.append("\n/* Symbols redirected to earlier glibc versions */\n");
+
+ foreach (var it in symbolMap.keys) {
+ var version = symbolMap.get (it);
+ string versionToUse;
+
+ /* If the symbol only has occurrences older than the minimum required glibc version,
+ * then there is no need to output anything for this symbol
+ */
+ if (filterMap.contains (it))
continue;
- foreach (var line in output.split("\n"))
- {
- var regex = new Regex("(.*)(GLIBC_)([0-9]+\\.([0-9]+\\.)*[0-9]+)(\\)?)([ ]*)(.+)");
-
- if (regex.match (line) && !("PRIVATE" in line))
- {
- var version = new VersionNumber (regex.split (line)[3]);
- var symbolName = regex.split (line)[7];
- var versionInMap = symbolMap.get (symbolName);
-
- /* Some versioning symbols exist in the objdump output, let's skip those */
- if (symbolName.has_prefix ("GLIBC"))
- continue;
-
- libcwrap_note (DF.COLLECT, () =>
- stdout.printf ("Selected symbol '%s' version '%s' from objdump line %s\n",
- symbolName, version.getString(), line));
-
- if (versionInMap == null)
- {
- symbolMap.set(symbolName, version);
-
- /* First occurance of the symbol, if it's older
- * than the minimum required, put it in that table also
- */
- if (minimumVersion.newerThan (version))
- {
- symbolsOlderThanMinimum.add(symbolName);
-
- libcwrap_note (DF.FILTER, () =>
- stdout.printf ("Adding symbol '%s %s' to the filter\n",
- symbolName, version.getString()));
- }
- }
- else
- {
- /* We want the newest possible version of a symbol which is older than the
- * minimum glibc version specified (or the only version of the symbol if
- * it's newer than the minimum version)
- */
- if(version.newerThan (versionInMap) && minimumVersion.newerThan (version))
- symbolMap.set(symbolName, version);
-
- /* While trucking along through the huge symbol list, remove symbols from
- * the 'safe to exclude' if there is a version found which is newer
- * than the minimum requirement
- */
- if (version.newerThan (minimumVersion))
- {
- symbolsOlderThanMinimum.remove(symbolName);
-
- libcwrap_note (DF.FILTER, () =>
- stdout.printf ("Removing symbol '%s %s' from the filter\n",
- symbolName, version.getString()));
- }
- }
- }
- else
- {
- libcwrap_note (DF.COLLECT, () => stdout.printf ("Rejected objdump line %s\n", line));
- }
+ /* If the only available symbol is > minimumVersion, then redirect it
+ * to a comprehensible linker error, otherwise redirect the symbol
+ * to it's existing version <= minimumVersion.
+ */
+ if (version.newerThan (minimumVersion)) {
+
+ versionToUse = "DONT_USE_THIS_VERSION_%s".printf (version.getString());
+ if (!overrides)
+ continue;
+
+ } else {
+
+ versionToUse = version.getString ();
+ if (overrides)
+ continue;
}
+
+ headerFile.append("__asm__(\".symver %s, %s@GLIBC_%s\");\n".printf(it, it, versionToUse));
}
-
+ }
+
+ private static void generateHeader () throws Error {
+ var headerFile = new StringBuilder ();
+
+ headerFile.append ("/* glibc bindings for target ABI version glibc " + minimumVersion.getString() + " */\n");
headerFile.append ("#if !defined (__LIBC_CUSTOM_BINDINGS_H__)\n");
headerFile.append ("\n");
headerFile.append ("# if !defined (__OBJC__) && !defined (__ASSEMBLER__)\n");
@@ -320,13 +334,8 @@ int main(string[] args)
/* For prettier output, let's output the redirected symbols first, and
* then output the ones which must not be used (new in glibc > minimumVersion).
*/
- append_symbols (headerFile, minimumVersion,
- symbolMap, symbolsOlderThanMinimum,
- false);
-
- append_symbols (headerFile, minimumVersion,
- symbolMap, symbolsOlderThanMinimum,
- true);
+ appendSymbols (headerFile, false);
+ appendSymbols (headerFile, true);
headerFile.append ("\n");
headerFile.append ("# if defined (__cplusplus)\n");
@@ -335,13 +344,6 @@ int main(string[] args)
headerFile.append ("# endif /* !defined (__OBJC__) && !defined (__ASSEMBLER__) */\n");
headerFile.append ("#endif\n");
- FileUtils.set_contents(filename, headerFile.str);
- }
- catch(Error e)
- {
- warning("%s", e.message);
- return 1;
+ FileUtils.set_contents (output, headerFile.str);
}
- stdout.printf(" OK\n");
- return 0;
}