]> mj.ucw.cz Git - leo.git/commitdiff
Switched to UCW configure and build system
authorMartin Mares <mj@ucw.cz>
Sun, 15 Jun 2014 19:44:16 +0000 (21:44 +0200)
committerMartin Mares <mj@ucw.cz>
Sun, 15 Jun 2014 19:44:16 +0000 (21:44 +0200)
14 files changed:
Makefile
build/Makebottom [new file with mode: 0644]
build/Maketop [new file with mode: 0644]
build/gen-dict [new file with mode: 0755]
build/lib-flags [new file with mode: 0755]
build/mergedeps [new file with mode: 0755]
configure [new file with mode: 0755]
default.cfg [new file with mode: 0644]
gen-dict [deleted file]
perl/UCW/Configure.pm [new file with mode: 0644]
perl/UCW/Configure/Build.pm [new file with mode: 0644]
perl/UCW/Configure/C.pm [new file with mode: 0644]
perl/UCW/Configure/Paths.pm [new file with mode: 0644]
perl/UCW/Configure/Pkg.pm [new file with mode: 0644]

index c0b1642274b438c1b3a1b753f30a058a8ed1e3e6..22214549483ecdccfd6fe42307691bf60325df97 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,63 +1,51 @@
-LIBUCW:=$(shell cd /home/mj/src/libucw/run && pwd)
-UCWCF:=$(shell PKG_CONFIG_PATH=$(LIBUCW)/lib/pkgconfig pkg-config --cflags libucw libucw-charset libucw-xml)
-UCWLF:=$(shell PKG_CONFIG_PATH=$(LIBUCW)/lib/pkgconfig pkg-config --libs libucw libucw-charset libucw-xml)
-FTCF:=$(shell freetype-config --cflags)
-FTLF:=$(shell freetype-config --libs)
-PANGOCF:=$(shell pkg-config pangoft2 --cflags)
-PANGOLF:=$(shell pkg-config pangoft2 --libs)
-
-CC=gcc
-LD=gcc
-COPT=-O2
-CFLAGS=$(COPT) -Wall -W -Wno-parentheses -Wstrict-prototypes -Wmissing-prototypes -Wundef -Wredundant-decls -Wno-missing-field-initializers -std=gnu99 $(UCWCF) -ggdb -DDEBUG_ASSERTS
-LDLIBS+=$(FTLF) $(PANGOLF) $(UCWLF) -lproj
-
-all: leo
-
-leo: leo.o xml.o osm.o svg.o svg-icon.o css-parse.o css-lex.o style.o css.o dict.o sym.o sym-point.o sym-line.o sym-text.o map.o shp.o
-
-INC=leo.h dict-keys.h dict-values.h dict-props.h osm.h svg.h style.h css.h dict.h map.h sym.h
-
-leo.o: leo.c $(INC)
-xml.o: xml.c $(INC)
-osm.o: osm.c $(INC)
-svg.o: svg.c $(INC)
-svg-icon.o: svg-icon.c $(INC)
-style.o: style.c $(INC)
-css.o: css.c $(INC)
-dict.o: dict.c $(INC)
-sym.o: sym.c $(INC)
-sym-point.o: sym-point.c $(INC)
-sym-line.o: sym-line.c $(INC)
-sym-text.o: sym-text.c $(INC)
-css-parse.o: css-parse.c $(INC)
-css-lex.o: css-lex.c $(INC) css-parse.c
-map.o: map.c $(INC)
-shp.o: shp.c $(INC)
-
-sym-text.o: CFLAGS+=$(FTCF) $(PANGOCF)
-
-css-parse.c: css-parse.y
-       bison --name-prefix=css_ --token-table --verbose --defines -o $@ $^
+# Makefile for Hic Est Leo
+
+all: runtree programs extras configs
+
+# Include configuration
+s=.
+-include obj/config.mk
+obj/config.mk:
+       @echo "You need to run configure first." && false
+
+BUILDSYS=$(s)/build
+
+# We will use the libucw build system
+include $(BUILDSYS)/Maketop
 
-dict-%.h: dict-%.t gen-dict
-       ./gen-dict <$< >$@
+PROGS+=$(o)/leo
+CFLAGS+=$(LIBUCW_CFLAGS)
 
-clean:
-       rm -f leo *.o css-parse.c css-parse.h css-parse.output tags
-       rm -f dict-keys.h dict-values.h dict-props.h
+LEO_MODULES=leo xml osm svg svg-icon css-parse css-lex style css dict sym sym-point sym-line sym-text map shp
+LEO_OBJECTS=$(addprefix $(o)/, $(addsuffix .o, $(LEO_MODULES)))
+$(o)/leo: $(LEO_OBJECTS)
 
-tags:
-       ctags *.[chy]
+$(o)/leo: LIBS+=$(LIBUCW_LIBS) $(LIBUCW_CHARSET_LIBS) $(LIBUCW_XML_LIBS) $(PANGOFT2_LIBS) $(FREETYPE_LIBS) -lproj
+
+$(o)/sym-text.o: CFLAGS+=$(FREETYPE_CFLAGS) $(PANGOFT2_CFLAGS)
+$(o)/svg-icon.o: CFLAGS+=$(LIBUCW_XML_CFLAGS)
+$(o)/xml.o: CFLAGS+=$(LIBUCW_XML_CFLAGS)
+
+$(LEO_OBJECTS): $(o)/dict-keys.h $(o)/dict-props.h $(o)/dict-values.h
+
+$(o)/css-parse.c: css-parse.y
+       bison --name-prefix=css_ --token-table --verbose --defines -o $@ $^
 
-upload:
-       rs output.pdf ps:poskole-beta/www/tmp/2014/mapa.pdf
+$(o)/dict-%.h: dict-%.t $(BUILDSYS)/gen-dict
+       build/gen-dict <$< >$@
 
-backup:
-       rs . camelot:a/priv/poskole/map/new/$$(date '+%Y%m%d-%H%M%S')/
+ifndef CONFIG_LOCAL
+install: all $(INSTALL_TARGETS)
+else
+install:
+       @echo "Nothing to install, this is a local build." && false
+endif
+.PHONY: install
 
-output.svg: leo dump.osm poskole.css
-       ./leo
+#output.svg: leo dump.osm poskole.css
+#      ./leo
+#
+#output.pdf: output.svg
+#      inkscape --export-pdf=output.pdf output.svg
 
-output.pdf: output.svg
-       inkscape --export-pdf=output.pdf output.svg
+include $(BUILDSYS)/Makebottom
diff --git a/build/Makebottom b/build/Makebottom
new file mode 100644 (file)
index 0000000..7ada953
--- /dev/null
@@ -0,0 +1,230 @@
+# Bottom part of Makefile for the UCW Libraries
+# (c) 1997--2008 Martin Mares <mj@ucw.cz>
+
+# The run tree
+
+DOCDIR=doc
+
+runtree: run/.tree-stamp $(addsuffix /.dir-stamp,$(addprefix $(o)/,$(DIRS)) $(addprefix run/$(DOCDIR)/,$(DOC_MODULES)))
+
+run/.tree-stamp: $(o)/config.mk
+       $(M)Creating runtree
+       $(Q)mkdir -p run $(addprefix run/, $(CONFIG_DIR) $(EXTRA_RUNDIRS) $(INSTALL_RUNDIRS))
+       $(Q)touch run/.tree-stamp
+
+# Miscellaneous targets
+
+programs: $(PROGS)
+datafiles: $(DATAFILES)
+tests: $(TESTS)
+configs: $(addprefix run/$(CONFIG_DIR)/,$(CONFIGS))
+docs: runtree $(DOCS) $(DOC_INDICES)
+
+tags:
+       etags `find . -name "*.[ch]"`
+
+# Black magic with dependencies. It would be more correct to make "depend.new"
+# a prerequisite for "depend", but "depend.new" often has the same timestamp
+# as "depend" which would confuse make a lot and either force remaking anyway
+# or (as in current versions of GNU make) erroneously skipping the remaking.
+
+-include $(o)/depend
+
+$(o)/depend: force
+       $(Q)if [ -s $(o)/depend.new ] ; then $(BUILDSYS)/mergedeps $(o)/depend $(o)/depend.new ; >$(o)/depend.new ; fi
+
+force:
+
+# Rules for directories
+
+%.dir-stamp:
+       $(Q)mkdir -p $(@D) && touch $@
+
+# Rules for configuration files
+
+run/$(CONFIG_DIR)/%: $(s)/$(CONFIG_SRC_DIR)/% $(o)/config.mk $(BUILDSYS)/genconf
+       $(M)CF $<
+       $(Q)$(BUILDSYS)/genconf $< $@ $(o)/config.mk
+
+$(o)/%.cf: $(s)/%.cf $(o)/config.mk $(BUILDSYS)/genconf
+       $(M)CF $<
+       $(Q)$(BUILDSYS)/genconf $< $@ $(o)/config.mk
+       $(Q)cp $@ run/$(CONFIG_DIR)/$(basename $(@F))
+
+# Rules for libraries
+
+%.a:
+       $(M)AR $@
+       $(Q)rm -f $@
+       $(Q)ar rcs $@ $^
+ifdef CONFIG_INSTALL_API
+       $(Q)$(call symlink-alias,$@,run/lib,$(*F)$(LIBNAME_INFIX).a)
+endif
+
+%.so:
+       $(M)LD $@
+       $(Q)$(CC) $(LSHARED) $(LDFLAGS) -o $@ $(shell PKG_CONFIG_PATH="$(PKG_CONFIG_PATH)" PKG_CONFIG_OPTS="$(PKG_CONFIG_OPTS)" $(BUILDSYS)/lib-flags $^) $(LIBS)
+       $(Q)$(call symlink-alias,$@,run/$(SO_RUNDIR),$(*F)$(SONAME_INFIX).so$(SONAME_SUFFIX))
+       $(Q)ln -fs $(*F)$(SONAME_INFIX).so$(SONAME_SUFFIX) run/$(SO_RUNDIR)/$(*F)$(SONAME_INFIX).so
+
+# On Darwin, gcc expects shared libraries in *.dylib instead of *.so.
+# Surprisingly, when a program is run, it suffices to have *.so files.
+# We don't want to mess up the whole build system with configurable
+# suffices and we also don't want to incur an overhead on Linux, so we
+# just create symbolic links on Darwin, if requested.
+%.dylib: %.so
+       cd $(dir $<) && ln -fs $(notdir $<) $(notdir $@)
+
+$(o)/%.pc: $(s)/%.pc $(o)/%$(LV).$(LS)
+       $(M)PC $<
+       $(Q)DEPS="$(shell $(BUILDSYS)/lib-deps $^)" LIBDIR=$(@D) $(BUILDSYS)/genconf $< $@ $(o)/config.mk
+       $(Q)mkdir -p $(o)/pkgconfig
+       $(Q)$(call symlink,$@,$(o)/pkgconfig)
+
+# Rules for public API
+
+ifdef CONFIG_INSTALL_API
+
+ifdef CONFIG_LOCAL
+# Need an absolute path
+API_ROOT:=$(shell pwd)/run
+API_LIBDIR=$(API_ROOT)/lib
+API_INCDIR=$(API_ROOT)/include
+else
+API_LIBDIR=$(INSTALL_LIB_DIR)
+API_INCDIR=$(INSTALL_INCLUDE_DIR)
+endif
+INSTALL_RUNDIRS+=include lib/pkgconfig
+api: $(API_INCLUDES) $(addprefix run/lib/pkgconfig/,$(addsuffix .pc,$(API_LIBS)))
+
+$(o)/%/.include-stamp:
+       $(Q)$(BUILDSYS)/install-includes $(<D) run/include/$(IDST) $(?F)
+       $(Q)touch $@
+
+run/lib/pkgconfig/%.pc:                # RHS supplied in the sub-makefile
+       $(M)PC-API $@
+       $(Q)sed <$< >$@ "s@^libdir=.*@libdir=$(API_LIBDIR)@;s@^incdir=.*@incdir=$(API_INCDIR)@"
+
+else
+api:
+endif
+
+# Rules for compiling C
+
+$(o)/%.o: $(s)/%.c $(o)/autoconf.h
+       $(M)CC $<
+       $(Q)DEPENDENCIES_OUTPUT="$(o)/depend.new $@" $(CC) $(CFLAGS) -c -o $@ $<
+
+$(o)/%.o: %.c $(o)/autoconf.h
+       $(M)CC $<
+       $(Q)DEPENDENCIES_OUTPUT="$(o)/depend.new $@" $(CC) $(CFLAGS) -c -o $@ $<
+
+%.o: %.c $(o)/autoconf.h
+       $(M)CC $<
+       $(Q)DEPENDENCIES_OUTPUT="$(o)/depend.new $@" $(CC) $(CFLAGS) -c -o $@ $<
+
+$(o)/%.oo: $(s)/%.c $(o)/autoconf.h
+       $(M)CC-SO $<
+       $(Q)DEPENDENCIES_OUTPUT="$(o)/depend.new $@" $(CC) $(CFLAGS) $(CSHARED) -c -o $@ $<
+
+$(o)/%.oo: %.c $(o)/autoconf.h
+       $(M)CC-SO $<
+       $(Q)DEPENDENCIES_OUTPUT="$(o)/depend.new $@" $(CC) $(CFLAGS) $(CSHARED) -c -o $@ $<
+
+%.oo: %.c $(o)/autoconf.h
+       $(M)CC-SO $<
+       $(Q)DEPENDENCIES_OUTPUT="$(o)/depend.new $@" $(CC) $(CFLAGS) $(CSHARED) -c -o $@ $<
+
+$(o)/%-tt.o: $(s)/%.c $(o)/autoconf.h
+       $(M)CC-TEST $<
+       $(Q)DEPENDENCIES_OUTPUT="$(o)/depend.new $@" $(CC) $(CFLAGS) -DTEST -c -o $@ $<
+
+# Rules for testing
+
+$(o)/%-t: $(o)/%-tt.o $(TESTING_DEPS)
+       $(M)LD-TEST $@
+       $(Q)$(CC) $(LDFLAGS) -o $@ $(shell PKG_CONFIG_PATH="$(PKG_CONFIG_PATH)" PKG_CONFIG_OPTS="$(PKG_CONFIG_OPTS)" $(BUILDSYS)/lib-flags $^) $(LIBS)
+
+$(o)/%.test: $(s)/%.t $(BUILDSYS)/tester
+       $(M)TEST $@
+       $(Q)$(BUILDSYS)/tester --rundir=run $(TESTERFLAGS) $< && touch $@
+
+# Rules for binaries
+
+BINDIR=bin
+
+$(o)/%: $(o)/%.o
+       $(M)LD $@
+       $(Q)$(CC) $(LDFLAGS) -o $@ $(shell PKG_CONFIG_PATH="$(PKG_CONFIG_PATH)" PKG_CONFIG_OPTS="$(PKG_CONFIG_OPTS)" $(BUILDSYS)/lib-flags $^) $(LIBS)
+       $(Q)$(call symlink,$@,run/$(BINDIR))
+
+$(o)/%: $(s)/%.sh $(o)/config.mk $(BUILDSYS)/genconf
+       $(M)PP $<
+       $(Q)$(BUILDSYS)/genconf $< $@ $(o)/config.mk
+       $(Q)chmod +x $@
+       $(Q)$(call symlink,$@,run/$(BINDIR))
+
+$(o)/%: %.sh $(o)/config.mk $(BUILDSYS)/genconf
+       $(M)PP $<
+       $(Q)$(BUILDSYS)/genconf $< $@ $(o)/config.mk
+       $(Q)chmod +x $@
+       $(Q)$(call symlink,$@,run/$(BINDIR))
+
+$(o)/%: $(s)/%.pl $(o)/config.mk $(BUILDSYS)/genconf
+       $(M)PP $<
+       $(Q)$(BUILDSYS)/genconf $< $@ $(o)/config.mk
+       $(Q)chmod +x $@
+       $(Q)$(call symlink,$@,run/$(BINDIR))
+
+$(o)/%: %.pl $(o)/config.mk $(BUILDSYS)/genconf
+       $(M)PP $<
+       $(Q)$(BUILDSYS)/genconf $< $@ $(o)/config.mk
+       $(Q)chmod +x $@
+       $(Q)$(call symlink,$@,run/$(BINDIR))
+
+PERL_MODULE_DIR=UCW
+
+$(o)/%.pm: $(s)/%.pm
+       $(M)"PM $< -> run/lib/perl5/$(PERL_MODULE_DIR)/$(@F)"
+       $(Q)cp $^ $@
+       $(Q)$(call symlink,$@,run/lib/perl5/$(PERL_MODULE_DIR))
+
+$(o)/%.pm: %.pm
+       $(M)"PM $< -> run/lib/perl/$(PERL_MODULE_DIR)/$(@F)"
+       $(Q)cp $^ $@
+       $(Q)$(call symlink,$@,run/lib/perl5/$(PERL_MODULE_DIR))
+
+# Rules for data files
+
+DATADIR=lib
+
+$(DATAFILES): $(o)/%: $(s)/%
+       $(M)DATA $<
+       $(Q)cp $^ $@
+       $(Q)$(call symlink,$@,run/$(DATADIR))
+
+# Rules for documentation
+
+$(o)/%.html: $(o)/%.txt $(BUILDSYS)/asciidoc.conf $(BUILDSYS)/asciidoc-xhtml.conf run/$(DOCDIR)/$(DOC_MODULE)/.dir-stamp
+       $(M)"DOC-HTML $<"
+       $(Q)asciidoc -e -f $(BUILDSYS)/asciidoc.conf -f $(BUILDSYS)/asciidoc-xhtml.conf -f $(HOST_PREFIX)/etc/asciidoc/asciidoc.conf -f $(HOST_PREFIX)/etc/asciidoc/xhtml11.conf $<
+       $(Q)$(call symlink,$@,run/$(DOCDIR)/$(DOC_MODULE))
+
+# In reality, we do not depend on the .txt files, but on the corresponding .deflist's.
+# However, the Makefile language cannot express that doc-extract generates both .txt
+# and .deflist, so we always use the .txt's in dependencies.
+$(patsubst %.html,%.txt,$(DOC_INDICES)): $(o)/%.txt: $(patsubst %.html,%.txt,$(DOCS)) $(BUILDSYS)/doc-defs
+       $(M)"DOC-DEFS $@"
+       $(Q)echo $@: $(DOC_HEAD) $(DOC_LIST) >> $(o)/depend.new
+       $(Q)$(BUILDSYS)/doc-defs $(DOC_HEAD) $@ $(DOC_LIST)
+
+$(patsubst %.html,%.txt,$(DOCS)): $(o)/%.txt: $(s)/%.txt $(BUILDSYS)/doc-extract
+       $(M)"DOC-EXT $<"
+       $(Q)$(BUILDSYS)/doc-extract $< $@ $(o)/depend.new $(s) $(patsubst %.txt,%.deflist,$@)
+
+# Don't delete intermediate targets. There shouldn't be any, but due to bugs
+# in GNU Make rules with targets in not-yet-existing directories are ignored
+# when searching for implicit rules and thence targets considered intermediate.
+.SECONDARY:
+
+.PHONY: all clean distclean runtree programs api datafiles force tags configs dust install docs tests
diff --git a/build/Maketop b/build/Maketop
new file mode 100644 (file)
index 0000000..b45187a
--- /dev/null
@@ -0,0 +1,97 @@
+# Top part of Makefile for the UCW Libraries
+# (c) 1997--2008 Martin Mares <mj@ucw.cz>
+
+# Set to 1 if you want verbose output
+V=0
+
+# Set to 'y' (or 'n') if you want to auto-confirm (auto-reject) all questions in build/installer
+CONFIRM=
+
+# Disable all built-in rules and variables. Speeds up make and simplifies debugging.
+MAKEFLAGS+=-rR
+
+CFLAGS=$(CLANG) $(COPT) $(CDEBUG) $(CWARNS) $(CEXTRA) -I. -I$(o) -I$(s)
+LDFLAGS=$(LOPT) $(LEXTRA)
+
+DIRS=
+PROGS=
+CONFIGS=
+CONFIG_SRC_DIR=$(CONFIG_DIR)
+TESTS=
+EXTRA_RUNDIRS=tmp log
+INSTALL_RUNDIRS=bin lib
+API_INCLUDES=
+API_LIBS=
+
+# Various files whose type does not fit into PROGS
+DATAFILES=
+
+ifdef CONFIG_DARWIN
+DYNAMIC_LIBRARIES=dylib
+SOEXT=bundle
+HOST_PREFIX=/sw
+else
+DYNAMIC_LIBRARIES=so
+SOEXT=so
+HOST_PREFIX=
+endif
+
+ifdef CONFIG_SHARED
+LS=$(DYNAMIC_LIBRARIES)
+OS=oo
+PKG_CONFIG_OPTS=
+else
+LS=a
+OS=o
+PKG_CONFIG_OPTS=--static
+endif
+LV=$(UCW_ABI_SUFFIX)
+
+SO_RUNDIR=lib
+
+# Whenever "make -s" (silent) is run, turn on verbose mode (paradoxical, but gives the right result)
+ifneq ($(findstring s,$(MAKEFLAGS)),)
+V=1
+endif
+
+# Define M (message) and Q (quiet command prefix) macros and also MAKESILENT passed to sub-makes
+ifeq ($(V),1)
+M=@\#
+Q=
+MAKESILENT=
+else
+M=@echo #
+Q=@
+MAKESILENT=-s
+endif
+
+# Clean needs to be a double-colon rule since we want sub-makefiles to be able
+# to define their own cleanup actions.
+dust::
+       rm -f `find . -path "*~" -or -name "\#*\#"`
+       rm -f allocs.tmp cscope.out TAGS
+
+clean:: dust
+       rm -rf `find obj/ucw -mindepth 1 -maxdepth 1 -not -name autoconf.h`
+       rm -rf `find obj -mindepth 1 -maxdepth 1 -not \( -name config.mk -o -name autoconf.h -o -name ucw \)`
+       rm -rf tests run/{bin,lib,include,.tree-stamp,doc}
+
+distclean:: clean
+       rm -rf obj run debian-tmp
+
+testclean::
+       rm -f `find obj -name "*.test"`
+
+docclean::
+       rm -f $(DOCS) $(patsubst %.html,%.txt,$(DOCS))
+
+# Extra default rules (appended to by submakefiles)
+extras::
+
+# Relative symlinks and other pathname manipulation macros
+empty:=
+space:=$(empty) $(empty)
+backref=$(subst $(space),/,$(patsubst %,..,$(subst /,$(space),$(1))))
+tack-on=$(if $(patsubst /%,,$(2)),$(1)/$(2),$(2))
+symlink=ln -sf $(call tack-on,$(call backref,$(2)),$(1)) $(2)/
+symlink-alias=ln -sf $(call tack-on,$(call backref,$(2)),$(1)) $(2)/$(3)
diff --git a/build/gen-dict b/build/gen-dict
new file mode 100755 (executable)
index 0000000..a221ec4
--- /dev/null
@@ -0,0 +1,16 @@
+#!/usr/bin/perl
+# Generate dict-*.h from dict-*.t
+
+use strict;
+use warnings;
+
+print "// Auto-generated by gen-dict\n";
+while (<STDIN>) {
+       chomp;
+       next if /^$/ or /^#/;
+       my $prop = $_;
+       my $sym = $_;
+       $sym =~ s{[^A-Za-z0-9_]}{_}g;
+       $sym =~ tr{a-z}{A-Z};
+       print "P($sym, \"$prop\")\n";
+}
diff --git a/build/lib-flags b/build/lib-flags
new file mode 100755 (executable)
index 0000000..29bb4e8
--- /dev/null
@@ -0,0 +1,24 @@
+#!/bin/bash
+#
+# A preprocessor for linker arguments, which replaces references to .pc
+# files by results of the proper calls to pkg-config.
+#
+# (c) 2007 Martin Mares <mj@ucw.cz>, placed under GNU LGPL
+#
+
+set -e
+
+PC=
+while [ -n "$1" ] ; do
+       case "$1" in
+               *.pc)   PC="$PC `basename $1 .pc`"
+                       ;;
+               *)      echo -n " $1"
+                       ;;
+       esac
+       shift
+done
+if [ -n "$PC" ] ; then
+       echo -n " "
+       PKG_CONFIG_PATH="$PKG_CONFIG_PATH:obj/pkgconfig" pkg-config $PKG_CONFIG_OPTS --libs $PC
+fi
diff --git a/build/mergedeps b/build/mergedeps
new file mode 100755 (executable)
index 0000000..e1c467d
--- /dev/null
@@ -0,0 +1,21 @@
+#!/usr/bin/perl
+
+@ARGV == 2 or die "Usage: mergedeps <base> <update>";
+foreach $a (@ARGV) {
+       open F, "$a" or next;
+       $t = "";
+       while (<F>) {
+               $t .= $_;
+               if (! /\\$/) {
+                       ($t =~ /^(.*):/) || die "Parse error at $t";
+                       $rules{$1} = $t;
+                       $t = "";
+               }
+       }
+       close F;
+}
+open(F,">" . $ARGV[0]) || die "Unable to write output file";
+foreach $a (sort keys %rules) {
+       print F $rules{$a};
+}
+close F;
diff --git a/configure b/configure
new file mode 100755 (executable)
index 0000000..4b2d61e
--- /dev/null
+++ b/configure
@@ -0,0 +1,39 @@
+#!/usr/bin/perl
+# Configure Script for Hic Est Leo
+# (c) 2014 Martin Mares <mj@ucw.cz>
+
+use warnings;
+use strict;
+
+our $srcdir;
+BEGIN {
+       my $pkgfile = "sym-line.c";
+       if (!defined ($srcdir = $ENV{"SRCDIR"})) {
+               if (-f $pkgfile) {
+                       $srcdir=".";
+               } elsif ($0 =~ m@^(.*)/configure$@ && -f "$1/$pkgfile") {
+                       $srcdir=$1;
+               } else {
+                       die "Don't know how to find myself. Please set SRCDIR manually.\n";
+               }
+       }
+}
+
+use lib "$srcdir/perl/";
+use UCW::Configure;
+
+Init($srcdir, "default.cfg");
+Log "### Configuring Hic Est Leo with configuration " . Get("CONFIG") . "\n";
+Include Get("CONFIG");
+require UCW::Configure::Paths;
+require UCW::Configure::C;
+require UCW::Configure::Pkg;
+
+UCW::Configure::Pkg::PkgConfig("libucw") or Fail("libucw is required");
+UCW::Configure::Pkg::PkgConfig("libucw-charset") or Fail("libucw-charset is required");
+UCW::Configure::Pkg::PkgConfig("libucw-xml") or Fail("libucw-xml is required");
+UCW::Configure::Pkg::PkgConfig("pangoft2") or Fail("pangoft2 is required");
+UCW::Configure::Pkg::TrivConfig("freetype", script => "freetype-config") or Fail("freetype2 is required");
+
+Finish();
+Log "\nConfigured, run `make' to build everything.\n";
diff --git a/default.cfg b/default.cfg
new file mode 100644 (file)
index 0000000..cf3ab41
--- /dev/null
@@ -0,0 +1,10 @@
+# Default configuration of Hic Est Leo
+
+# By default, compile everything for local use without installation
+Set("CONFIG_LOCAL");
+
+# Include debugging code
+Set("CONFIG_DEBUG");
+
+# Return success
+1;
diff --git a/gen-dict b/gen-dict
deleted file mode 100755 (executable)
index a221ec4..0000000
--- a/gen-dict
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/usr/bin/perl
-# Generate dict-*.h from dict-*.t
-
-use strict;
-use warnings;
-
-print "// Auto-generated by gen-dict\n";
-while (<STDIN>) {
-       chomp;
-       next if /^$/ or /^#/;
-       my $prop = $_;
-       my $sym = $_;
-       $sym =~ s{[^A-Za-z0-9_]}{_}g;
-       $sym =~ tr{a-z}{A-Z};
-       print "P($sym, \"$prop\")\n";
-}
diff --git a/perl/UCW/Configure.pm b/perl/UCW/Configure.pm
new file mode 100644 (file)
index 0000000..5d458ad
--- /dev/null
@@ -0,0 +1,226 @@
+#      Perl module for UCW Configure Scripts
+#
+#      (c) 2005--2010 Martin Mares <mj@ucw.cz>
+#
+#      This software may be freely distributed and used according to the terms
+#      of the GNU Lesser General Public License.
+
+package UCW::Configure;
+
+use strict;
+use warnings;
+
+BEGIN {
+       # The somewhat hairy Perl export mechanism
+       use Exporter();
+       our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
+       $VERSION = 1.0;
+       @ISA = qw(Exporter);
+       @EXPORT = qw(&Init &Log &Notice &Warn &Fail &IsSet &IsGiven &Set &UnSet &Append &Override &Get &Test &TestBool &Include &Finish &FindFile &TryFindFile &DebugDump &PostConfig &AtWrite);
+       @EXPORT_OK = qw();
+       %EXPORT_TAGS = ();
+}
+
+our %vars;
+our %overriden;
+our @postconfigs;
+our @atwrites;
+
+sub DebugDump() {
+       print "VARS:\n";
+       print "$_: $vars{$_}\n" foreach( keys %vars );
+}
+
+sub Log($) {
+       print @_;
+}
+
+sub Notice($) {
+       print @_ if $vars{"VERBOSE"};
+}
+
+sub Warn($) {
+       print "WARNING: ", @_;
+}
+
+sub Fail($) {
+       Log("ERROR: " . (shift @_) . "\n");
+       exit 1;
+}
+
+sub IsSet($) {
+       my ($x) = @_;
+       return exists $vars{$x};
+}
+
+sub IsGiven($) {
+       my ($x) = @_;
+       return exists $overriden{$x};
+}
+
+sub Get($) {
+       my ($x) = @_;
+       return $vars{$x};
+}
+
+sub Set($;$) {
+       my ($x,$y) = @_;
+       $y=1 unless defined $y;
+       $vars{$x}=$y unless $overriden{$x};
+}
+
+sub UnSet($) {
+       my ($x) = @_;
+       delete $vars{$x} unless $overriden{$x};
+}
+
+sub Append($$) {
+       my ($x,$y) = @_;
+       Set($x, (IsSet($x) ? (Get($x) . " $y") : $y));
+}
+
+sub Override($;$) {
+       my ($x,$y) = @_;
+       $y=1 unless defined $y;
+       $vars{$x}=$y;
+       $overriden{$x} = 1;
+}
+
+sub Test($$$) {
+       my ($var,$msg,$sub) = @_;
+       Log "$msg ... ";
+       if (IsSet($var)) {
+               Log Get($var) . " (preset)\n";
+       } else {
+               my $val = &$sub();
+               Set($var, $val);
+               Log "$val\n";
+       }
+}
+
+sub TestBool($$$) {
+       my ($var,$msg,$sub) = @_;
+       Log "$msg ... ";
+       if (IsSet($var) || IsGiven($var)) {
+               Log ((Get($var) ? "yes" : "no") . " (set)\n");
+       } else {
+               my ($val, $comment) = &$sub();
+               Set($var, $val);
+               Log (($val ? "yes" : "no") . "\n");
+       }
+}
+
+sub TryFindFile($) {
+       my ($f) = @_;
+       if (-f $f) {
+               return $f;
+       } elsif ($f !~ /^\// && -f (Get("SRCDIR")."/$f")) {
+               return Get("SRCDIR")."/$f";
+       } else {
+               return undef;
+       }
+}
+
+sub FindFile($) {
+       my ($f) = @_;
+       my $F;
+       defined ($F = TryFindFile($f)) or Fail "Cannot find file $f";
+       return $F;
+}
+
+sub Init($$) {
+       my ($srcdir,$defconfig) = @_;
+       sub usage($) {
+               my ($dc) = @_;
+               print STDERR "Usage: [<srcdir>/]configure " . (defined $dc ? "[" : "") . "<config-name>" . (defined $dc ? "]" : "") .
+                       " [<option>[=<value>] | -<option>] ...\n";
+               exit 1;
+       }
+       Set('CONFIG' => $defconfig) if defined $defconfig;
+       if (@ARGV) {
+               usage($defconfig) if $ARGV[0] eq "--help";
+               if (!defined($defconfig) || $ARGV[0] !~ /^-?[A-Z][A-Z0-9_]*(=|$)/) {
+                       # This does not look like an option, so read it as a file name
+                       Set('CONFIG' => shift @ARGV);
+               }
+       }
+       Set("SRCDIR", $srcdir);
+
+       foreach my $x (@ARGV) {
+               if ($x =~ /^(\w+)=(.*)/) {
+                       Override($1 => $2);
+               } elsif ($x =~ /^-(\w+)$/) {
+                       Override($1 => 0);
+                       delete $vars{$1};
+               } elsif ($x =~ /^(\w+)$/) {
+                       Override($1 => 1);
+               } else {
+                       print STDERR "Invalid option $x\n";
+                       exit 1;
+               }
+       }
+
+       defined Get("CONFIG") or usage($defconfig);
+       if (!TryFindFile(Get("CONFIG"))) {
+               TryFindFile(Get("CONFIG")."/config") or Fail "Cannot find configuration " . Get("CONFIG");
+               Override("CONFIG" => Get("CONFIG")."/config");
+       }
+}
+
+sub Include($) {
+       my ($f) = @_;
+       $f = FindFile($f);
+       Notice "Loading configuration $f\n";
+       require $f;
+}
+
+sub PostConfig(&) {
+       unshift @postconfigs, $_[0];
+}
+
+sub AtWrite(&) {
+       unshift @atwrites, $_[0];
+}
+
+sub Finish() {
+       for my $post (@postconfigs) {
+               &$post();
+       }
+
+       print "\n";
+
+       if (Get("SRCDIR") ne ".") {
+               Log "Preparing for compilation from directory " . Get("SRCDIR") . " to obj/ ... ";
+               -l "src" and unlink "src";
+               symlink Get("SRCDIR"), "src" or Fail "Cannot link source directory to src: $!";
+               Override("SRCDIR" => "src");
+               -l "Makefile" and unlink "Makefile";
+               -f "Makefile" and Fail "Makefile already exists";
+               symlink "src/Makefile", "Makefile" or Fail "Cannot link Makefile: $!";
+       } else {
+               Log "Preparing for compilation from current directory to obj/ ... ";
+       }
+       if (-d "obj") {
+               `rm -rf obj`; Fail "Cannot delete old obj directory" if $?;
+       }
+       -d "obj" or mkdir("obj", 0777) or Fail "Cannot create obj directory: $!";
+       -d "obj/ucw" or mkdir("obj/ucw", 0777) or Fail "Cannot create obj/ucw directory: $!";
+       Log "done\n";
+
+       Log "Generating config.mk ... ";
+       open X, ">obj/config.mk" or Fail $!;
+       print X "# Generated automatically by $0, please don't touch manually.\n";
+       foreach my $x (sort keys %vars) {
+               print X "$x=$vars{$x}\n";
+       }
+       print X "s=\${SRCDIR}\n";
+       print X "o=obj\n";
+       close X;
+       Log "done\n";
+
+       for my $wr (@atwrites) {
+               &$wr();
+       }
+}
+
+1;  # OK
diff --git a/perl/UCW/Configure/Build.pm b/perl/UCW/Configure/Build.pm
new file mode 100644 (file)
index 0000000..042d14c
--- /dev/null
@@ -0,0 +1,26 @@
+# UCW Library configuration system: find UCW build system
+# (c) 2008 Michal Vaner <vorner@ucw.cz>
+
+# This module asks pkg-config for a path to UCW build system
+# and sets propper variables for it (or fails, as it is expected
+# the build system is crucial).
+
+package UCW::Configure::Build;
+use UCW::Configure;
+
+use strict;
+use warnings;
+
+if (!IsGiven("BUILDSYS")) {
+       Test("BUILDSYS", "Looking for UCW build system", sub {
+               my $path=`pkg-config libucw --variable=build_system`;
+               if($? || not defined $path) {
+                       Fail("Not found (is libUCW installed and PKG_CONFIG_PATH set?)");
+               }
+               chomp $path;
+               return $path;
+       });
+}
+
+# We succeeded
+1;
diff --git a/perl/UCW/Configure/C.pm b/perl/UCW/Configure/C.pm
new file mode 100644 (file)
index 0000000..e961ca0
--- /dev/null
@@ -0,0 +1,240 @@
+# UCW Library configuration system: OS and C compiler
+# (c) 2005--2012 Martin Mares <mj@ucw.cz>
+# (c) 2006 Robert Spalek <robert@ucw.cz>
+# (c) 2008 Michal Vaner <vorner@ucw.cz>
+
+### OS ###
+
+package UCW::Configure::C;
+use UCW::Configure;
+
+use strict;
+use warnings;
+
+Test("OS", "Checking on which OS we run", sub {
+       my $os = `uname`;
+       chomp $os;
+       Fail "Unable to determine OS type" if $? || $os eq "";
+       return $os;
+});
+
+if (Get("OS") eq "Linux") {
+       Set("CONFIG_LINUX");
+} elsif (Get("OS") eq "Darwin") {
+       Set("CONFIG_DARWIN");
+} else {
+       Fail "Don't know how to run on this operating system.";
+}
+
+### Compiler ###
+
+# Default compiler
+Test("CC", "Checking for C compiler", sub { return "gcc"; });
+
+# GCC version
+Test("GCCVER", "Checking for GCC version", sub {
+       my $gcc = Get("CC");
+       my $ver = `$gcc --version | sed '2,\$d; s/^\\(.* \\)*\\([0-9]*\\.[0-9]*\\).*/\\2/'`;
+       chomp $ver;
+       Fail "Unable to determine GCC version" if $? || $ver eq "";
+       return $ver;
+});
+my ($gccmaj, $gccmin) = split(/\./, Get("GCCVER"));
+my $gccver = 1000*$gccmaj + $gccmin;
+$gccver >= 3000 or Fail "GCC older than 3.0 doesn't support C99 well enough.";
+
+### CPU ###
+
+Test("ARCH", "Checking for machine architecture", sub {
+       #
+       # We have to ask GCC for the target architecture, because it may
+       # differ from what uname tells us. This can happen even if we are
+       # not cross-compiling, for example on Linux with amd64 kernel, but
+       # i386 userspace.
+       #
+       my $gcc = Get("CC");
+       my $mach = `$gcc -dumpmachine 2>/dev/null`;
+       if (!$? && $mach ne "") {
+               $mach =~ s/-.*//;
+       } else {
+               $mach = `uname -m`;
+               Fail "Unable to determine machine type" if $? || $mach eq "";
+       }
+       chomp $mach;
+       if ($mach =~ /^i[0-9]86$/) {
+               return "i386";
+       } elsif ($mach =~ /^(x86[_-]|amd)64$/) {
+               return "amd64";
+       } else {
+               return "unknown ($mach)";
+       }
+});
+
+my $arch = Get("ARCH");
+if ($arch eq 'i386') {
+       Set("CPU_I386");
+       UnSet("CPU_64BIT_POINTERS");
+       Set("CPU_LITTLE_ENDIAN");
+       UnSet("CPU_BIG_ENDIAN");
+       Set("CPU_ALLOW_UNALIGNED");
+       Set("CPU_STRUCT_ALIGN" => 4);
+} elsif ($arch eq "amd64") {
+       Set("CPU_AMD64");
+       Set("CPU_64BIT_POINTERS");
+       Set("CPU_LITTLE_ENDIAN");
+       UnSet("CPU_BIG_ENDIAN");
+       Set("CPU_ALLOW_UNALIGNED");
+       Set("CPU_STRUCT_ALIGN" => 8);
+} elsif (!Get("CPU_LITTLE_ENDIAN") && !Get("CPU_BIG_ENDIAN")) {
+       Fail "Architecture not recognized, please set CPU_xxx variables manually.";
+}
+
+### Compiler and its Options ###
+
+# C flags: tell the compiler we're speaking C99, and disable common symbols
+Set("CLANG" => "-std=gnu99 -fno-common");
+
+# C optimizations
+Set("COPT" => '-O2');
+if ($arch =~ /^(i386|amd64)$/ && Get("CONFIG_EXACT_CPU")) {
+       if ($gccver >= 4002) {
+               Append('COPT', '-march=native');
+       } else {
+               Warn "CONFIG_EXACT_CPU not supported with old GCC, ignoring.\n";
+       }
+}
+
+# C optimizations for highly exposed code
+Set("COPT2" => '-O3');
+
+# Warnings
+Set("CWARNS" => '-Wall -W -Wno-parentheses -Wstrict-prototypes -Wmissing-prototypes');
+Set("CWARNS_OFF" => '');
+
+# Linker flags
+Set("LOPT" => "");
+
+# Extra libraries
+Set("LIBS" => "");
+
+# Extra flags for compiling and linking shared libraries
+Set("CSHARED" => '-fPIC');
+Append("LOPT" => "-Wl,--rpath-link,run/lib");
+if (Get("INSTALL_LIB_DIR") eq "/usr/lib") {
+       Set("SO_LINK_PATH" => '');
+}
+else {
+       Set("SO_LINK_PATH" => "-Wl,--rpath," . Get("INSTALL_LIB_DIR"));
+       AtWrite {
+               # FIXME: This is a hack. GCC would otherwise fail to link binaries.
+               my $libdir = Get("INSTALL_LIB_DIR");
+               if (IsSet("CONFIG_SHARED") && !(-d $libdir)) {
+                       `install -d -m 755 $libdir`; Fail("Cannot create $libdir") if $?;
+               }
+       };
+}
+if (IsSet("CONFIG_DARWIN")) {
+       Set("LSHARED" => '-dynamiclib -install_name $(@F)$(SONAME_SUFFIX) -undefined dynamic_lookup');
+} else {
+       Set("LSHARED" => '-shared -Wl,-soname,$(@F)$(SONAME_SUFFIX)');
+}
+
+# Extra switches depending on GCC version:
+if ($gccver == 3000) {
+       Append("COPT" => "-fstrict-aliasing");
+} elsif ($gccver == 3003) {
+       Append("CWARNS" => "-Wundef -Wredundant-decls");
+       Append("COPT" => "-finline-limit=20000 --param max-inline-insns-auto=1000");
+} elsif ($gccver == 3004) {
+       Append("CWARNS" => "-Wundef -Wredundant-decls");
+       Append("COPT" => "-finline-limit=2000 --param large-function-insns=5000 --param inline-unit-growth=200 --param large-function-growth=400");
+} elsif ($gccver >= 4000) {
+       Append("CWARNS" => "-Wundef -Wredundant-decls -Wno-pointer-sign -Wdisabled-optimization -Wno-missing-field-initializers");
+       Append("CWARNS_OFF" => "-Wno-pointer-sign");
+       Append("COPT" => "-finline-limit=5000 --param large-function-insns=5000 --param inline-unit-growth=200 --param large-function-growth=400");
+} else {
+       Warn "Don't know anything about this GCC version, using default switches.\n";
+}
+
+if (IsSet("CONFIG_DEBUG")) {
+       # If debugging:
+       Set("DEBUG_ASSERTS");
+       Set("DEBUG_DIE_BY_ABORT") if Get("CONFIG_DEBUG") > 1;
+       Set("CDEBUG" => "-ggdb");
+} else {
+       # If building a release version:
+       Append("COPT" => "-fomit-frame-pointer");
+       Append("LOPT" => "-s");
+}
+
+if (IsSet("CONFIG_DARWIN")) {
+       # gcc-4.0 on Darwin doesn't set this in the gnu99 mode
+       Append("CLANG" => "-fnested-functions");
+       # Directory hierarchy of the fink project
+       Append("LIBS" => "-L/sw/lib");
+       Append("COPT" => "-I/sw/include");
+}
+
+### Compiling test programs ###
+
+sub TestCompile($$) {
+       my ($testname, $source) = @_;
+       my $dir = "conftest-$testname";
+       `rm -rf $dir && mkdir $dir`; $? and Fail "Cannot initialize $dir";
+
+       open SRC, ">$dir/conftest.c";
+       print SRC $source;
+       close SRC;
+
+       my $cmd = join(" ",
+               map { defined($_) ? $_ : "" }
+                       "cd $dir &&",
+                       Get("CC"), Get("CLANG"), Get("COPT"), Get("CEXTRA"), Get("LIBS"),
+                       "conftest.c", "-o", "conftest",
+                       ">conftest.log", "2>&1"
+               );
+       `$cmd`;
+       my $result = !$?;
+
+       `rm -rf $dir` unless Get("KEEP_CONFTEST");
+
+       return $result;
+}
+
+### Writing C headers with configuration ###
+
+sub ConfigHeader($$) {
+       my ($hdr, $rules) = @_;
+       Log "Generating $hdr ... ";
+       open X, ">obj/$hdr" or Fail $!;
+       print X "/* Generated automatically by $0, please don't touch manually. */\n";
+
+       sub match_rules($$) {
+               my ($rules, $name) = @_;
+               for (my $i=0; $i < scalar @$rules; $i++) {
+                       my ($r, $v) = ($rules->[$i], $rules->[$i+1]);
+                       return $v if $name =~ $r;
+               }
+               return 0;
+       }
+
+       foreach my $x (sort keys %UCW::Configure::vars) {
+               next unless match_rules($rules, $x);
+               my $v = $UCW::Configure::vars{$x};
+               # Try to add quotes if necessary
+               $v = '"' . $v . '"' unless ($v =~ /^"/ || $v =~ /^\d*$/);
+               print X "#define $x $v\n";
+       }
+       close X;
+       Log "done\n";
+}
+
+AtWrite {
+       ConfigHeader("autoconf.h", [
+               # Symbols with "_" anywhere in their name are exported
+               "_" => 1
+       ]);
+};
+
+# Return success
+1;
diff --git a/perl/UCW/Configure/Paths.pm b/perl/UCW/Configure/Paths.pm
new file mode 100644 (file)
index 0000000..d03c90d
--- /dev/null
@@ -0,0 +1,58 @@
+# UCW Library configuration system: installation paths
+# (c) 2005--2009 Martin Mares <mj@ucw.cz>
+# (c) 2006 Robert Spalek <robert@ucw.cz>
+# (c) 2008 Michal Vaner <vorner@ucw.cz>
+
+package UCW::Configure::Paths;
+use UCW::Configure;
+
+use strict;
+use warnings;
+
+Log "Determining installation prefix ... ";
+if (IsSet("CONFIG_LOCAL")) {
+       if (IsSet("CONFIG_RELATIVE_PATHS")) {
+               Log("local build with relative paths\n");
+               Set("INSTALL_PREFIX", "");
+       }
+       else {
+               Log("local build with absolute paths\n");
+               my $cwd = `pwd`; Fail("Cannot get current working directory") if $?;
+               chomp $cwd;
+               Set("INSTALL_PREFIX", "$cwd/run/");
+       }
+       Set("INSTALL_USR_PREFIX", Get("INSTALL_PREFIX"));
+       Set("INSTALL_VAR_PREFIX", Get("INSTALL_PREFIX"));
+} else {
+       Set("PREFIX", "/usr/local") unless IsSet("PREFIX");
+       my $ipx = Get("PREFIX");
+       $ipx =~ s{/$}{};
+       Set("INSTALL_PREFIX", "$ipx/");
+       my $upx = ($ipx eq "" ? "/usr/" : "$ipx/");
+       Set("INSTALL_USR_PREFIX", $upx);
+       $upx =~ s{^/usr\b}{/var};
+       Set("INSTALL_VAR_PREFIX", $upx);
+       Log(Get("PREFIX") . "\n");
+}
+
+Set('CONFIG_DIR', 'etc') unless IsSet('CONFIG_DIR');
+Set('INSTALL_CONFIG_DIR', Get('INSTALL_PREFIX') . Get('CONFIG_DIR'));
+Set('INSTALL_BIN_DIR', Get('INSTALL_USR_PREFIX') . 'bin');
+Set('INSTALL_SBIN_DIR', Get('INSTALL_USR_PREFIX') . 'sbin');
+Set('INSTALL_LIB_DIR', Get('INSTALL_USR_PREFIX') . 'lib');
+Set('INSTALL_INCLUDE_DIR', Get('INSTALL_USR_PREFIX') . 'include');
+Set('INSTALL_PKGCONFIG_DIR', Get('INSTALL_USR_PREFIX') . 'lib/pkgconfig');
+Set('INSTALL_SHARE_DIR', Get('INSTALL_USR_PREFIX') . 'share');
+Set('INSTALL_MAN_DIR', Get('INSTALL_USR_PREFIX') . 'share/man');
+Set('INSTALL_LOG_DIR', Get('INSTALL_VAR_PREFIX') . 'log');
+Set('INSTALL_STATE_DIR', Get('INSTALL_VAR_PREFIX') . 'lib');
+Set('INSTALL_RUN_DIR', Get('INSTALL_VAR_PREFIX') . 'run');
+Set('INSTALL_DOC_DIR', Get('INSTALL_USR_PREFIX') . 'share/doc');
+Set('INSTALL_PERL_DIR', Get('INSTALL_LIB_DIR') . '/perl5');
+
+# Remember PKG_CONFIG_PATH used for building, so that it will be propagated to
+# pkg-config's run locally in the makefiles.
+Set("PKG_CONFIG_PATH", $ENV{"PKG_CONFIG_PATH"}) if defined $ENV{"PKG_CONFIG_PATH"};
+
+# We succeeded
+1;
diff --git a/perl/UCW/Configure/Pkg.pm b/perl/UCW/Configure/Pkg.pm
new file mode 100644 (file)
index 0000000..5f3dc33
--- /dev/null
@@ -0,0 +1,120 @@
+# UCW Library configuration system: pkg-config and friends
+# (c) 2008 Martin Mares <mj@ucw.cz>
+
+package UCW::Configure::Pkg;
+use UCW::Configure;
+
+use strict;
+use warnings;
+
+require Exporter;
+our @ISA = qw(Exporter);
+our @EXPORT = qw(&TryCmd &PkgConfig &TrivConfig);
+
+sub TryCmd($) {
+       my ($cmd) = @_;
+       my $res = `$cmd`;
+       defined $res or return;
+       chomp $res;
+       return $res unless $?;
+       return;
+}
+
+sub maybe_manually($) {
+       my ($n) = @_;
+       if (IsGiven($n)) {
+               if (Get("$n")) { Log "YES (set manually)\n"; }
+               else { Log "NO (set manually)\n"; }
+               return 1;
+       }
+       return 0;
+}
+
+sub PkgConfigTool() {
+       Log "Checking for pkg-config ... ";
+       if (!maybe_manually("CONFIG_HAVE_PKGCONFIG")) {
+               my $ver = TryCmd("pkg-config --version 2>/dev/null");
+               if (!defined $ver) {
+                       Log("NONE\n");
+                       Set("CONFIG_HAVE_PKGCONFIG", 0);
+               } else {
+                       Log("YES: version $ver\n");
+                       Set("CONFIG_HAVE_PKGCONFIG", 1);
+                       Set("CONFIG_VER_PKGCONFIG", $ver);
+               }
+       }
+       return Get("CONFIG_HAVE_PKGCONFIG");
+}
+
+sub PkgConfig($@) {
+       my $pkg = shift @_;
+       my %opts = @_;
+       my $upper = $pkg; $upper =~ tr/a-z/A-Z/; $upper =~ s/[^0-9A-Z]+/_/g;
+       PkgConfigTool() unless IsSet("CONFIG_HAVE_PKGCONFIG");
+       Log "Checking for package $pkg ... ";
+       maybe_manually("CONFIG_HAVE_$upper") and return Get("CONFIG_HAVE_$upper");
+       if (!Get("CONFIG_HAVE_PKGCONFIG")) {
+               Log("NONE: pkg-config missing\n");
+               return 0;
+       }
+       my $ver = TryCmd("pkg-config --modversion $pkg 2>/dev/null");
+       if (!defined $ver) {
+               Log("NONE\n");
+               return 0;
+       }
+       if (defined($opts{minversion})) {
+               my $min = $opts{minversion};
+               if (!defined TryCmd("pkg-config --atleast-version=$min $pkg")) {
+                       Log("NO: version $ver is too old (need >= $min)\n");
+                       return 0;
+               }
+       }
+       Log("YES: version $ver\n");
+       Set("CONFIG_HAVE_$upper" => 1);
+       Set("CONFIG_VER_$upper" => $ver);
+       my $cf = TryCmd("pkg-config --cflags $pkg");
+       Set("${upper}_CFLAGS" => $cf) if defined $cf;
+       my $lf = TryCmd("pkg-config --libs $pkg");
+       Set("${upper}_LIBS" => $lf) if defined $lf;
+       return 1;
+}
+
+sub ver_norm($) {
+       my ($v) = @_;
+       return join(".", map { sprintf("%05s", $_) } split(/\./, $v));
+}
+
+sub TrivConfig($@) {
+       my $pkg = shift @_;
+       my %opts = @_;
+       my $upper = $pkg; $upper =~ tr/a-z/A-Z/; $upper =~ s/[^0-9A-Z]+/_/g;
+       Log "Checking for package $pkg ... ";
+       maybe_manually("CONFIG_HAVE_$upper") and return Get("CONFIG_HAVE_$upper");
+       my $pc = $opts{script};
+       my $ver = TryCmd("$pc --version 2>/dev/null");
+       if (!defined $ver) {
+               Log("NONE\n");
+               return 0;
+       }
+       if (defined($opts{minversion})) {
+               my $min = $opts{minversion};
+               if (ver_norm($ver) lt ver_norm($min)) {
+                       Log("NO: version $ver is too old (need >= $min)\n");
+                       return 0;
+               }
+       }
+       Log("YES: version $ver\n");
+       Set("CONFIG_HAVE_$upper" => 1);
+       Set("CONFIG_VER_$upper" => $ver);
+
+       my $want = $opts{want};
+       defined $want or $want = ["cflags", "libs"];
+       for my $w (@$want) {
+               my $uw = $w; $uw =~ tr/a-z-/A-Z_/;
+               my $cf = TryCmd("$pc --$w");
+               Set("${upper}_${uw}" => $cf) if defined $cf;
+       }
+       return 1;
+}
+# We succeeded
+1;