build: Replace error2.pl by error2.c.
authorAndre Noll <maan@systemlinux.org>
Fri, 13 Sep 2013 01:41:15 +0000 (01:41 +0000)
committerAndre Noll <maan@systemlinux.org>
Sun, 1 Dec 2013 10:51:58 +0000 (11:51 +0100)
The C code is much faster than the old perl script. Since the resulting
executable runs on the build system, the compiler for this system
must be called to compile error2.c. The new HOSTCC variable takes
care of this.

With this patch applied, the only remaining dependencies on perl are
help2man and autoconf.

Makefile.in
configure.ac
error2.c [new file with mode: 0644]
error2.pl [deleted file]

index c500fb9..4160d25 100644 (file)
@@ -9,8 +9,11 @@ PACKAGE_VERSION := @PACKAGE_VERSION@
 PACKAGE_STRING := @PACKAGE_STRING@
 INSTALL := @install@
 STRIP := $(CROSS_COMPILE)strip
+HOSTCC ?= cc
 executables := $(addprefix para_, @executables@)
 ggo_descriptions_declared := @ggo_descriptions_declared@
+object_executable_matrix := @object_executable_matrix@
+
 
 GENGETOPT := @gengetopt@
 HELP2MAN := @help2man@
@@ -37,6 +40,7 @@ man_dir := $(build_dir)/man/man1
 cmdline_dir := $(build_dir)/cmdline
 m4depdir := $(build_dir)/m4deps
 help2man_dir := $(build_dir)/help2man
+hostbin_dir := $(build_dir)/host/bin
 
 DEBUG_CPPFLAGS += -g -Wunused -Wundef -W
 DEBUG_CPPFLAGS += -Wredundant-decls
@@ -106,7 +110,7 @@ man: $(man_pages)
 tarball: $(tarball)
 
 $(object_dir) $(man_dir) $(ggo_dir) $(cmdline_dir) $(dep_dir) $(m4depdir) \
-               $(help2man_dir):
+               $(help2man_dir) $(hostbin_dir):
        $(Q) $(MKDIR_P) $@
 
 -include $(m4_ggo_dir)/makefile
@@ -153,6 +157,12 @@ $(man_dir)/%.1: $(help2man_dir)/% | $(man_dir)
        @[ -z "$(Q)" ] || echo 'MAN $<'
        $(Q) $(HELP2MAN) -N ./$< > $@
 
+$(hostbin_dir)/error2: error2.c | $(hostbin_dir)
+       @[ -z "$(Q)" ] || echo 'HCC $<'
+       $(Q) $(HOSTCC) -o $@ $<
+error2.h: $(hostbin_dir)/error2
+       @[ -z "$(Q)" ] || echo 'ER2 $<'
+       @echo "$(object_executable_matrix)" | $< > $@
 $(object_dir)/crypt.o: crypt.c | $(object_dir)
        @[ -z "$(Q)" ] || echo 'CC $<'
        $(Q) $(CC) -c -o $@ $(CPPFLAGS) $(DEBUG_CPPFLAGS) @openssl_cppflags@ $<
index 9927c60..dec0636 100644 (file)
@@ -1332,8 +1332,6 @@ else
        AC_MSG_WARN([no curses lib, cannot build para_gui])
 fi
 ############################################################# error2.h
-AC_MSG_NOTICE(creating error2.h)
-
 # these are always built
 all_errlist_objs="
        $recv_errlist_objs
@@ -1363,10 +1361,14 @@ fi
 
 all_errlist_objs="$(echo $all_errlist_objs | tr ' ' '\n' | sort | uniq)"
 
+object_executable_matrix=
 for i in $executables; do
-       echo "$i: "
-       eval echo \$${i}_errlist_objs
-done | ./error2.pl > error2.h
+       eval objs=\$${i}_errlist_objs
+       object_executable_matrix="$object_executable_matrix $i: $objs"
+done
+# use echo to replace newlines by space
+AC_SUBST(object_executable_matrix, $(echo $object_executable_matrix))
+
 for obj in $all_errlist_objs; do
        SS="$SS SS_$(echo $obj | tr 'a-z' 'A-Z'),"
 done
@@ -1374,7 +1376,6 @@ AC_DEFINE_UNQUOTED(DEFINE_ERRLIST_OBJECT_ENUM,
        [enum {$SS NUM_SS}],
        [list of all objects that use the paraslash error facility]
 )
-
 ################################################################## status items
 
 status_items="basename status num_played mtime bitrate frequency file_size
diff --git a/error2.c b/error2.c
new file mode 100644 (file)
index 0000000..630d4c7
--- /dev/null
+++ b/error2.c
@@ -0,0 +1,151 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <assert.h>
+#include <inttypes.h>
+#include <string.h>
+#include <stdbool.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <ctype.h>
+
+// #define DEBUG
+#ifdef DEBUG
+       #define log(fmt, ...) fprintf(stderr, "%s: " fmt, __FUNCTION__, ## __VA_ARGS__)
+#else
+       #define log(...) do {;} while (0)
+#endif /* DEBUG*/
+
+#define HASH_TABLE_BITS 8
+#define HASH_TABLE_SIZE (1 << HASH_TABLE_BITS)
+
+/* number of executables seen so far */
+static int num_exe;
+
+struct hash_table_entry {
+       char *key;
+       /* only used for objecs, not for executables */
+       unsigned exe_bitmask;
+};
+
+static struct hash_table_entry exe_table[HASH_TABLE_SIZE];
+static struct hash_table_entry obj_table[HASH_TABLE_SIZE];
+
+/* no need for anything sophisticated here */
+static int hash_token(const char *tok)
+{
+       uint32_t tmp = 31415927;
+       const uint8_t *src = (typeof(src))tok;
+
+       for (; *src; src++) {
+               tmp *= 27182817;
+               tmp += *tok;
+       }
+       return tmp % HASH_TABLE_SIZE;
+}
+
+static inline bool slot_empty(int idx, struct hash_table_entry *table)
+{
+       return table[idx].key == NULL;
+}
+
+static char *safe_strdup(const char *str)
+{
+       char *result = strdup(str);
+       if (result)
+               return result;
+       errno = ENOMEM;
+       perror("strdup");
+       exit(EXIT_FAILURE);
+}
+
+static bool lookup(const char *tok, struct hash_table_entry *table, int *idx)
+{
+       int i, h = hash_token(tok);
+
+       for (i = 0; i < HASH_TABLE_SIZE; i++) {
+               *idx = (h + i) % HASH_TABLE_SIZE;
+               if (slot_empty(*idx, table))
+                       return false;
+               if (!strcmp(table[*idx].key, tok))
+                       return true;
+       }
+       log ("hash table full !?\n");
+       exit(EXIT_FAILURE);
+}
+
+static bool insert(const char *tok, struct hash_table_entry *table, int *idx)
+{
+       if (lookup(tok, table, idx))
+               return false; /* not inserted */
+       table[*idx].key = safe_strdup(tok);
+       return true;
+}
+
+static void process_token(char *tok)
+{
+       int idx;
+       size_t len = strlen(tok);
+
+       assert(len > 0);
+       if (tok[len - 1] == ':') {
+               tok[len - 1] = '\0';
+               if (insert(tok, exe_table, &idx)) { /* new exe */
+                       log("exe #%d: '%s', idx: %d\n", num_exe, tok, idx);
+                       num_exe++;
+               }
+       } else {
+               if (num_exe == 0) {
+                       log("invalid input\n");
+                       exit(EXIT_FAILURE);
+               }
+               insert(tok, obj_table, &idx);
+               obj_table[idx].exe_bitmask |= (1 << (num_exe - 1));
+       }
+}
+
+static void print_ss_enum(int idx)
+{
+       char *s = obj_table[idx].key;
+
+       printf("SS_ENUM(");
+       for (; *s; s++)
+               printf("%c", toupper(*s));
+       printf(");\n");
+}
+
+static void dump_bipolar(void)
+{
+       int i, j;
+
+       for (i = 0; i < HASH_TABLE_SIZE; i++) {
+               if (slot_empty(i, obj_table))
+                       continue;
+               printf("#ifdef MAIN_INPUT_FILE_IS_%s\n", obj_table[i].key);
+               for (j = 0; j < HASH_TABLE_SIZE; j++) {
+                       unsigned mi, mj;
+                       if (slot_empty(j, obj_table))
+                               continue;
+                       mi = obj_table[i].exe_bitmask;
+                       mj = obj_table[j].exe_bitmask;
+                       if ((mi & mj) == mi)
+                               print_ss_enum(j);
+               }
+               printf("#endif\n");
+       }
+}
+
+int main(void)
+{
+       int ret;
+
+       for (;;) {
+               char tok[100];
+               ret = scanf("%96s", tok);
+               if (ret != 1)
+                       break;
+               process_token(tok);
+       }
+       dump_bipolar();
+       return 0;
+}
diff --git a/error2.pl b/error2.pl
deleted file mode 100755 (executable)
index 78ff2c5..0000000
--- a/error2.pl
+++ /dev/null
@@ -1,58 +0,0 @@
-#!/usr/bin/env perl
-
-use warnings;
-use strict;
-
-my %matrix;
-my @executables;
-my %objects;
-
-sub make_matrix
-{
-       my ($line, $e, @fields, $field);
-
-       while (defined($line = <>)) {
-               chomp($line);
-               if ($line =~ "^ *\$") {
-                       next;
-               }
-               @fields = split(" ", $line);
-               while (defined(($field = shift(@fields)))) {
-                       if ($field =~ ":\$") {
-                               $field =~ s/://;
-                               $e = $field;
-                               push(@executables, $e);
-                               next;
-                       }
-                       $matrix{$e . ">" . $field} = 1;
-                       $objects{$field} = 1;
-               }
-       }
-}
-
-sub print_safe_objects
-{
-       my @objs = keys(%objects);
-       my ($o1, $o2, $e);
-
-       foreach $o1 (@objs) {
-               print("#ifdef MAIN_INPUT_FILE_IS_$o1\n");
-               O2: foreach $o2 (@objs) {
-                       foreach $e (@executables) {
-                               if (!defined($matrix{$e . ">" . $o1})) {
-                                       next;
-                               }
-                               if (defined($matrix{$e . ">" . $o2})) {
-                                       next;
-                               }
-                               next O2;
-                       }
-                       $_ = $o2;
-                       tr/a-z/A-Z/;
-                       printf("SS_ENUM(%s);\n", $_);
-               }
-               print("#endif\n");
-       }
-}
-make_matrix;
-print_safe_objects;