Repository: lucy-charmonizer
Updated Branches:
  refs/heads/master 698cd055f -> 58cdc20d5


Rework Makefile API for binaries

Expose a higher level API to build binaries with make. The new
chaz_MakeBinary class allows to scan a directory for source files
and to pass separate compiler flags for each binary.

Improve building of shared libaries:

- Add compatibility version on Darwin (Mach-O).
- Build import library with GCC on Windows.
- Add soname with Sun CC (untested).

Remove the chaz_Library class.

Rework detection of the platform's make utility. We don't use this
information for now, so it's purely informative.


Project: http://git-wip-us.apache.org/repos/asf/lucy-charmonizer/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucy-charmonizer/commit/1ce65627
Tree: http://git-wip-us.apache.org/repos/asf/lucy-charmonizer/tree/1ce65627
Diff: http://git-wip-us.apache.org/repos/asf/lucy-charmonizer/diff/1ce65627

Branch: refs/heads/master
Commit: 1ce65627296988138352d7634a056920ac8b0354
Parents: 698cd05
Author: Nick Wellnhofer <wellnho...@aevum.de>
Authored: Sat Jul 2 19:19:06 2016 +0200
Committer: Nick Wellnhofer <wellnho...@aevum.de>
Committed: Tue Jul 5 00:55:51 2016 +0200

----------------------------------------------------------------------
 Makefile                        |   4 +-
 Makefile.MSVC                   |   4 +-
 Makefile.MinGW                  |   4 +-
 buildbin/meld.pl                |   1 -
 src/Charmonizer/Core/CFlags.c   |  70 ++-
 src/Charmonizer/Core/CFlags.h   |  14 +-
 src/Charmonizer/Core/Compiler.c |  93 +++-
 src/Charmonizer/Core/Compiler.h |  38 ++
 src/Charmonizer/Core/Library.c  | 174 --------
 src/Charmonizer/Core/Library.h  |  75 ----
 src/Charmonizer/Core/Make.c     | 810 +++++++++++++++++++++++++----------
 src/Charmonizer/Core/Make.h     | 118 ++---
 src/Charmonizer/Probe/Floats.c  |   2 +-
 13 files changed, 829 insertions(+), 578 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucy-charmonizer/blob/1ce65627/Makefile
----------------------------------------------------------------------
diff --git a/Makefile b/Makefile
index 8221cac..c5ffdd9 100644
--- a/Makefile
+++ b/Makefile
@@ -27,11 +27,11 @@ PERL=/usr/bin/perl
 
 TESTS= TestDirManip TestFuncMacro TestHeaders TestIntegers TestLargeFiles 
TestUnusedVars TestVariadicMacros
 
-OBJS= charmonize.o src/Charmonizer/Core/CFlags.o src/Charmonizer/Core/CLI.o 
src/Charmonizer/Core/Compiler.o src/Charmonizer/Core/ConfWriter.o 
src/Charmonizer/Core/ConfWriterC.o src/Charmonizer/Core/ConfWriterPerl.o 
src/Charmonizer/Core/ConfWriterPython.o src/Charmonizer/Core/ConfWriterRuby.o 
src/Charmonizer/Core/HeaderChecker.o src/Charmonizer/Core/Library.o 
src/Charmonizer/Core/Make.o src/Charmonizer/Core/OperatingSystem.o 
src/Charmonizer/Core/Util.o src/Charmonizer/Probe.o 
src/Charmonizer/Probe/AtomicOps.o src/Charmonizer/Probe/Booleans.o 
src/Charmonizer/Probe/BuildEnv.o src/Charmonizer/Probe/DirManip.o 
src/Charmonizer/Probe/Floats.o src/Charmonizer/Probe/FuncMacro.o 
src/Charmonizer/Probe/Headers.o src/Charmonizer/Probe/Integers.o 
src/Charmonizer/Probe/LargeFiles.o src/Charmonizer/Probe/Memory.o 
src/Charmonizer/Probe/RegularExpressions.o src/Charmonizer/Probe/Strings.o 
src/Charmonizer/Probe/SymbolVisibility.o src/Charmonizer/Probe/UnusedVars.o 
src/Charmonizer/Probe/VariadicMacros.
 o
+OBJS= charmonize.o src/Charmonizer/Core/CFlags.o src/Charmonizer/Core/CLI.o 
src/Charmonizer/Core/Compiler.o src/Charmonizer/Core/ConfWriter.o 
src/Charmonizer/Core/ConfWriterC.o src/Charmonizer/Core/ConfWriterPerl.o 
src/Charmonizer/Core/ConfWriterPython.o src/Charmonizer/Core/ConfWriterRuby.o 
src/Charmonizer/Core/HeaderChecker.o src/Charmonizer/Core/Make.o 
src/Charmonizer/Core/OperatingSystem.o src/Charmonizer/Core/Util.o 
src/Charmonizer/Probe.o src/Charmonizer/Probe/AtomicOps.o 
src/Charmonizer/Probe/Booleans.o src/Charmonizer/Probe/BuildEnv.o 
src/Charmonizer/Probe/DirManip.o src/Charmonizer/Probe/Floats.o 
src/Charmonizer/Probe/FuncMacro.o src/Charmonizer/Probe/Headers.o 
src/Charmonizer/Probe/Integers.o src/Charmonizer/Probe/LargeFiles.o 
src/Charmonizer/Probe/Memory.o src/Charmonizer/Probe/RegularExpressions.o 
src/Charmonizer/Probe/Strings.o src/Charmonizer/Probe/SymbolVisibility.o 
src/Charmonizer/Probe/UnusedVars.o src/Charmonizer/Probe/VariadicMacros.o
 
 TEST_OBJS= src/Charmonizer/Test.o src/Charmonizer/Test/TestDirManip.o 
src/Charmonizer/Test/TestFuncMacro.o src/Charmonizer/Test/TestHeaders.o 
src/Charmonizer/Test/TestIntegers.o src/Charmonizer/Test/TestLargeFiles.o 
src/Charmonizer/Test/TestUnusedVars.o src/Charmonizer/Test/TestVariadicMacros.o
 
-HEADERS= src/Charmonizer/Core/CFlags.h src/Charmonizer/Core/CLI.h 
src/Charmonizer/Core/Compiler.h src/Charmonizer/Core/ConfWriter.h 
src/Charmonizer/Core/ConfWriterC.h src/Charmonizer/Core/ConfWriterPerl.h 
src/Charmonizer/Core/ConfWriterPython.h src/Charmonizer/Core/ConfWriterRuby.h 
src/Charmonizer/Core/Defines.h src/Charmonizer/Core/HeaderChecker.h 
src/Charmonizer/Core/Library.h src/Charmonizer/Core/Make.h 
src/Charmonizer/Core/OperatingSystem.h src/Charmonizer/Core/Util.h 
src/Charmonizer/Probe.h src/Charmonizer/Probe/AtomicOps.h 
src/Charmonizer/Probe/Booleans.h src/Charmonizer/Probe/BuildEnv.h 
src/Charmonizer/Probe/DirManip.h src/Charmonizer/Probe/Floats.h 
src/Charmonizer/Probe/FuncMacro.h src/Charmonizer/Probe/Headers.h 
src/Charmonizer/Probe/Integers.h src/Charmonizer/Probe/LargeFiles.h 
src/Charmonizer/Probe/Memory.h src/Charmonizer/Probe/RegularExpressions.h 
src/Charmonizer/Probe/Strings.h src/Charmonizer/Probe/SymbolVisibility.h 
src/Charmonizer/Probe/UnusedVars.h src/Charmonizer/
 Probe/VariadicMacros.h src/Charmonizer/Test.h
+HEADERS= src/Charmonizer/Core/CFlags.h src/Charmonizer/Core/CLI.h 
src/Charmonizer/Core/Compiler.h src/Charmonizer/Core/ConfWriter.h 
src/Charmonizer/Core/ConfWriterC.h src/Charmonizer/Core/ConfWriterPerl.h 
src/Charmonizer/Core/ConfWriterPython.h src/Charmonizer/Core/ConfWriterRuby.h 
src/Charmonizer/Core/Defines.h src/Charmonizer/Core/HeaderChecker.h 
src/Charmonizer/Core/Make.h src/Charmonizer/Core/OperatingSystem.h 
src/Charmonizer/Core/Util.h src/Charmonizer/Probe.h 
src/Charmonizer/Probe/AtomicOps.h src/Charmonizer/Probe/Booleans.h 
src/Charmonizer/Probe/BuildEnv.h src/Charmonizer/Probe/DirManip.h 
src/Charmonizer/Probe/Floats.h src/Charmonizer/Probe/FuncMacro.h 
src/Charmonizer/Probe/Headers.h src/Charmonizer/Probe/Integers.h 
src/Charmonizer/Probe/LargeFiles.h src/Charmonizer/Probe/Memory.h 
src/Charmonizer/Probe/RegularExpressions.h src/Charmonizer/Probe/Strings.h 
src/Charmonizer/Probe/SymbolVisibility.h src/Charmonizer/Probe/UnusedVars.h 
src/Charmonizer/Probe/VariadicMacros.h src/Char
 monizer/Test.h
 
 CLEANABLE= $(OBJS) $(PROGNAME) $(CHARMONY_H) $(TEST_OBJS) $(TESTS) 
 

http://git-wip-us.apache.org/repos/asf/lucy-charmonizer/blob/1ce65627/Makefile.MSVC
----------------------------------------------------------------------
diff --git a/Makefile.MSVC b/Makefile.MSVC
index 155140c..ec9654a 100644
--- a/Makefile.MSVC
+++ b/Makefile.MSVC
@@ -27,11 +27,11 @@ PERL=/usr/bin/perl
 
 TESTS= TestDirManip.exe TestFuncMacro.exe TestHeaders.exe TestIntegers.exe 
TestLargeFiles.exe TestUnusedVars.exe TestVariadicMacros.exe
 
-OBJS= charmonize.obj src\Charmonizer\Core\CFlags.obj 
src\Charmonizer\Core\CLI.obj src\Charmonizer\Core\Compiler.obj 
src\Charmonizer\Core\ConfWriter.obj src\Charmonizer\Core\ConfWriterC.obj 
src\Charmonizer\Core\ConfWriterPerl.obj 
src\Charmonizer\Core\ConfWriterPython.obj 
src\Charmonizer\Core\ConfWriterRuby.obj src\Charmonizer\Core\HeaderChecker.obj 
src\Charmonizer\Core\Library.obj src\Charmonizer\Core\Make.obj 
src\Charmonizer\Core\OperatingSystem.obj src\Charmonizer\Core\Util.obj 
src\Charmonizer\Probe.obj src\Charmonizer\Probe\AtomicOps.obj 
src\Charmonizer\Probe\Booleans.obj src\Charmonizer\Probe\BuildEnv.obj 
src\Charmonizer\Probe\DirManip.obj src\Charmonizer\Probe\Floats.obj 
src\Charmonizer\Probe\FuncMacro.obj src\Charmonizer\Probe\Headers.obj 
src\Charmonizer\Probe\Integers.obj src\Charmonizer\Probe\LargeFiles.obj 
src\Charmonizer\Probe\Memory.obj src\Charmonizer\Probe\RegularExpressions.obj 
src\Charmonizer\Probe\Strings.obj src\Charmonizer\Probe\SymbolVisibility.obj 
src\Charmonizer\
 Probe\UnusedVars.obj src\Charmonizer\Probe\VariadicMacros.obj
+OBJS= charmonize.obj src\Charmonizer\Core\CFlags.obj 
src\Charmonizer\Core\CLI.obj src\Charmonizer\Core\Compiler.obj 
src\Charmonizer\Core\ConfWriter.obj src\Charmonizer\Core\ConfWriterC.obj 
src\Charmonizer\Core\ConfWriterPerl.obj 
src\Charmonizer\Core\ConfWriterPython.obj 
src\Charmonizer\Core\ConfWriterRuby.obj src\Charmonizer\Core\HeaderChecker.obj 
src\Charmonizer\Core\Make.obj src\Charmonizer\Core\OperatingSystem.obj 
src\Charmonizer\Core\Util.obj src\Charmonizer\Probe.obj 
src\Charmonizer\Probe\AtomicOps.obj src\Charmonizer\Probe\Booleans.obj 
src\Charmonizer\Probe\BuildEnv.obj src\Charmonizer\Probe\DirManip.obj 
src\Charmonizer\Probe\Floats.obj src\Charmonizer\Probe\FuncMacro.obj 
src\Charmonizer\Probe\Headers.obj src\Charmonizer\Probe\Integers.obj 
src\Charmonizer\Probe\LargeFiles.obj src\Charmonizer\Probe\Memory.obj 
src\Charmonizer\Probe\RegularExpressions.obj src\Charmonizer\Probe\Strings.obj 
src\Charmonizer\Probe\SymbolVisibility.obj src\Charmonizer\Probe\UnusedVars.obj 
src\Charmoni
 zer\Probe\VariadicMacros.obj
 
 TEST_OBJS= src\Charmonizer\Test.obj src\Charmonizer\Test\TestDirManip.obj 
src\Charmonizer\Test\TestFuncMacro.obj src\Charmonizer\Test\TestHeaders.obj 
src\Charmonizer\Test\TestIntegers.obj src\Charmonizer\Test\TestLargeFiles.obj 
src\Charmonizer\Test\TestUnusedVars.obj 
src\Charmonizer\Test\TestVariadicMacros.obj
 
-HEADERS= src\Charmonizer\Core\CFlags.h src\Charmonizer\Core\CLI.h 
src\Charmonizer\Core\Compiler.h src\Charmonizer\Core\ConfWriter.h 
src\Charmonizer\Core\ConfWriterC.h src\Charmonizer\Core\ConfWriterPerl.h 
src\Charmonizer\Core\ConfWriterPython.h src\Charmonizer\Core\ConfWriterRuby.h 
src\Charmonizer\Core\Defines.h src\Charmonizer\Core\HeaderChecker.h 
src\Charmonizer\Core\Library.h src\Charmonizer\Core\Make.h 
src\Charmonizer\Core\OperatingSystem.h src\Charmonizer\Core\Util.h 
src\Charmonizer\Probe.h src\Charmonizer\Probe\AtomicOps.h 
src\Charmonizer\Probe\Booleans.h src\Charmonizer\Probe\BuildEnv.h 
src\Charmonizer\Probe\DirManip.h src\Charmonizer\Probe\Floats.h 
src\Charmonizer\Probe\FuncMacro.h src\Charmonizer\Probe\Headers.h 
src\Charmonizer\Probe\Integers.h src\Charmonizer\Probe\LargeFiles.h 
src\Charmonizer\Probe\Memory.h src\Charmonizer\Probe\RegularExpressions.h 
src\Charmonizer\Probe\Strings.h src\Charmonizer\Probe\SymbolVisibility.h 
src\Charmonizer\Probe\UnusedVars.h src\Charmonizer\
 Probe\VariadicMacros.h src\Charmonizer\Test.h
+HEADERS= src\Charmonizer\Core\CFlags.h src\Charmonizer\Core\CLI.h 
src\Charmonizer\Core\Compiler.h src\Charmonizer\Core\ConfWriter.h 
src\Charmonizer\Core\ConfWriterC.h src\Charmonizer\Core\ConfWriterPerl.h 
src\Charmonizer\Core\ConfWriterPython.h src\Charmonizer\Core\ConfWriterRuby.h 
src\Charmonizer\Core\Defines.h src\Charmonizer\Core\HeaderChecker.h 
src\Charmonizer\Core\Make.h src\Charmonizer\Core\OperatingSystem.h 
src\Charmonizer\Core\Util.h src\Charmonizer\Probe.h 
src\Charmonizer\Probe\AtomicOps.h src\Charmonizer\Probe\Booleans.h 
src\Charmonizer\Probe\BuildEnv.h src\Charmonizer\Probe\DirManip.h 
src\Charmonizer\Probe\Floats.h src\Charmonizer\Probe\FuncMacro.h 
src\Charmonizer\Probe\Headers.h src\Charmonizer\Probe\Integers.h 
src\Charmonizer\Probe\LargeFiles.h src\Charmonizer\Probe\Memory.h 
src\Charmonizer\Probe\RegularExpressions.h src\Charmonizer\Probe\Strings.h 
src\Charmonizer\Probe\SymbolVisibility.h src\Charmonizer\Probe\UnusedVars.h 
src\Charmonizer\Probe\VariadicMacros.h src\Char
 monizer\Test.h
 
 CLEANABLE= $(OBJS) $(PROGNAME) $(CHARMONY_H) $(TEST_OBJS) $(TESTS) *.pdb
 

http://git-wip-us.apache.org/repos/asf/lucy-charmonizer/blob/1ce65627/Makefile.MinGW
----------------------------------------------------------------------
diff --git a/Makefile.MinGW b/Makefile.MinGW
index 0c3104a..3cbad7f 100644
--- a/Makefile.MinGW
+++ b/Makefile.MinGW
@@ -27,11 +27,11 @@ PERL=/usr/bin/perl
 
 TESTS= TestDirManip.exe TestFuncMacro.exe TestHeaders.exe TestIntegers.exe 
TestLargeFiles.exe TestUnusedVars.exe TestVariadicMacros.exe
 
-OBJS= charmonize.o src\Charmonizer\Core\CFlags.o src\Charmonizer\Core\CLI.o 
src\Charmonizer\Core\Compiler.o src\Charmonizer\Core\ConfWriter.o 
src\Charmonizer\Core\ConfWriterC.o src\Charmonizer\Core\ConfWriterPerl.o 
src\Charmonizer\Core\ConfWriterPython.o src\Charmonizer\Core\ConfWriterRuby.o 
src\Charmonizer\Core\HeaderChecker.o src\Charmonizer\Core\Library.o 
src\Charmonizer\Core\Make.o src\Charmonizer\Core\OperatingSystem.o 
src\Charmonizer\Core\Util.o src\Charmonizer\Probe.o 
src\Charmonizer\Probe\AtomicOps.o src\Charmonizer\Probe\Booleans.o 
src\Charmonizer\Probe\BuildEnv.o src\Charmonizer\Probe\DirManip.o 
src\Charmonizer\Probe\Floats.o src\Charmonizer\Probe\FuncMacro.o 
src\Charmonizer\Probe\Headers.o src\Charmonizer\Probe\Integers.o 
src\Charmonizer\Probe\LargeFiles.o src\Charmonizer\Probe\Memory.o 
src\Charmonizer\Probe\RegularExpressions.o src\Charmonizer\Probe\Strings.o 
src\Charmonizer\Probe\SymbolVisibility.o src\Charmonizer\Probe\UnusedVars.o 
src\Charmonizer\Probe\VariadicMacros.
 o
+OBJS= charmonize.o src\Charmonizer\Core\CFlags.o src\Charmonizer\Core\CLI.o 
src\Charmonizer\Core\Compiler.o src\Charmonizer\Core\ConfWriter.o 
src\Charmonizer\Core\ConfWriterC.o src\Charmonizer\Core\ConfWriterPerl.o 
src\Charmonizer\Core\ConfWriterPython.o src\Charmonizer\Core\ConfWriterRuby.o 
src\Charmonizer\Core\HeaderChecker.o src\Charmonizer\Core\Make.o 
src\Charmonizer\Core\OperatingSystem.o src\Charmonizer\Core\Util.o 
src\Charmonizer\Probe.o src\Charmonizer\Probe\AtomicOps.o 
src\Charmonizer\Probe\Booleans.o src\Charmonizer\Probe\BuildEnv.o 
src\Charmonizer\Probe\DirManip.o src\Charmonizer\Probe\Floats.o 
src\Charmonizer\Probe\FuncMacro.o src\Charmonizer\Probe\Headers.o 
src\Charmonizer\Probe\Integers.o src\Charmonizer\Probe\LargeFiles.o 
src\Charmonizer\Probe\Memory.o src\Charmonizer\Probe\RegularExpressions.o 
src\Charmonizer\Probe\Strings.o src\Charmonizer\Probe\SymbolVisibility.o 
src\Charmonizer\Probe\UnusedVars.o src\Charmonizer\Probe\VariadicMacros.o
 
 TEST_OBJS= src\Charmonizer\Test.o src\Charmonizer\Test\TestDirManip.o 
src\Charmonizer\Test\TestFuncMacro.o src\Charmonizer\Test\TestHeaders.o 
src\Charmonizer\Test\TestIntegers.o src\Charmonizer\Test\TestLargeFiles.o 
src\Charmonizer\Test\TestUnusedVars.o src\Charmonizer\Test\TestVariadicMacros.o
 
-HEADERS= src\Charmonizer\Core\CFlags.h src\Charmonizer\Core\CLI.h 
src\Charmonizer\Core\Compiler.h src\Charmonizer\Core\ConfWriter.h 
src\Charmonizer\Core\ConfWriterC.h src\Charmonizer\Core\ConfWriterPerl.h 
src\Charmonizer\Core\ConfWriterPython.h src\Charmonizer\Core\ConfWriterRuby.h 
src\Charmonizer\Core\Defines.h src\Charmonizer\Core\HeaderChecker.h 
src\Charmonizer\Core\Library.h src\Charmonizer\Core\Make.h 
src\Charmonizer\Core\OperatingSystem.h src\Charmonizer\Core\Util.h 
src\Charmonizer\Probe.h src\Charmonizer\Probe\AtomicOps.h 
src\Charmonizer\Probe\Booleans.h src\Charmonizer\Probe\BuildEnv.h 
src\Charmonizer\Probe\DirManip.h src\Charmonizer\Probe\Floats.h 
src\Charmonizer\Probe\FuncMacro.h src\Charmonizer\Probe\Headers.h 
src\Charmonizer\Probe\Integers.h src\Charmonizer\Probe\LargeFiles.h 
src\Charmonizer\Probe\Memory.h src\Charmonizer\Probe\RegularExpressions.h 
src\Charmonizer\Probe\Strings.h src\Charmonizer\Probe\SymbolVisibility.h 
src\Charmonizer\Probe\UnusedVars.h src\Charmonizer\
 Probe\VariadicMacros.h src\Charmonizer\Test.h
+HEADERS= src\Charmonizer\Core\CFlags.h src\Charmonizer\Core\CLI.h 
src\Charmonizer\Core\Compiler.h src\Charmonizer\Core\ConfWriter.h 
src\Charmonizer\Core\ConfWriterC.h src\Charmonizer\Core\ConfWriterPerl.h 
src\Charmonizer\Core\ConfWriterPython.h src\Charmonizer\Core\ConfWriterRuby.h 
src\Charmonizer\Core\Defines.h src\Charmonizer\Core\HeaderChecker.h 
src\Charmonizer\Core\Make.h src\Charmonizer\Core\OperatingSystem.h 
src\Charmonizer\Core\Util.h src\Charmonizer\Probe.h 
src\Charmonizer\Probe\AtomicOps.h src\Charmonizer\Probe\Booleans.h 
src\Charmonizer\Probe\BuildEnv.h src\Charmonizer\Probe\DirManip.h 
src\Charmonizer\Probe\Floats.h src\Charmonizer\Probe\FuncMacro.h 
src\Charmonizer\Probe\Headers.h src\Charmonizer\Probe\Integers.h 
src\Charmonizer\Probe\LargeFiles.h src\Charmonizer\Probe\Memory.h 
src\Charmonizer\Probe\RegularExpressions.h src\Charmonizer\Probe\Strings.h 
src\Charmonizer\Probe\SymbolVisibility.h src\Charmonizer\Probe\UnusedVars.h 
src\Charmonizer\Probe\VariadicMacros.h src\Char
 monizer\Test.h
 
 CLEANABLE= $(OBJS) $(PROGNAME) $(CHARMONY_H) $(TEST_OBJS) $(TESTS) 
 

http://git-wip-us.apache.org/repos/asf/lucy-charmonizer/blob/1ce65627/buildbin/meld.pl
----------------------------------------------------------------------
diff --git a/buildbin/meld.pl b/buildbin/meld.pl
index 48a5885..b4db46c 100755
--- a/buildbin/meld.pl
+++ b/buildbin/meld.pl
@@ -67,7 +67,6 @@ if ( !@probes ) {
 }
 
 my @core = qw(
-    Library
     CFlags
     CLI
     Compiler

http://git-wip-us.apache.org/repos/asf/lucy-charmonizer/blob/1ce65627/src/Charmonizer/Core/CFlags.c
----------------------------------------------------------------------
diff --git a/src/Charmonizer/Core/CFlags.c b/src/Charmonizer/Core/CFlags.c
index 1c177b5..a1f4684 100644
--- a/src/Charmonizer/Core/CFlags.c
+++ b/src/Charmonizer/Core/CFlags.c
@@ -20,7 +20,6 @@
 #include "Charmonizer/Core/Compiler.h"
 #include "Charmonizer/Core/Util.h"
 #include "Charmonizer/Core/OperatingSystem.h"
-#include "Charmonizer/Core/Library.h"
 
 struct chaz_CFlags {
     int   style;
@@ -244,55 +243,44 @@ chaz_CFlags_hide_symbols(chaz_CFlags *flags) {
 }
 
 void
-chaz_CFlags_link_shared_library(chaz_CFlags *flags) {
-    const char *string;
+chaz_CFlags_link_shared_library(chaz_CFlags *flags, const char *basename,
+                                const char *version,
+                                const char *major_version) {
+    char *string = NULL;
+
     if (flags->style == CHAZ_CFLAGS_STYLE_MSVC) {
-        string = "/DLL";
+        string = chaz_Util_strdup("/DLL");
     }
     else if (flags->style == CHAZ_CFLAGS_STYLE_GNU) {
-        if (chaz_CC_binary_format() == CHAZ_CC_BINFMT_MACHO) {
-            string = "-dynamiclib";
+        int binary_format = chaz_CC_binary_format();
+
+        if (binary_format == CHAZ_CC_BINFMT_MACHO) {
+            string = chaz_Util_join(" ", "-dynamiclib", "-current_version",
+                                    version, "-compatibility_version",
+                                    major_version, NULL);
         }
-        else {
-            string = "-shared";
+        else if (binary_format == CHAZ_CC_BINFMT_ELF) {
+            string = chaz_Util_join("", "-shared -Wl,-soname,lib", basename,
+                                    ".so.", major_version, NULL);
+        }
+        else if (binary_format == CHAZ_CC_BINFMT_PE) {
+            string = chaz_Util_join("", "-shared -Wl,--out-implib,lib",
+                                    basename, "-", major_version, ".dll.a",
+                                    NULL);
         }
     }
     else if (flags->style == CHAZ_CFLAGS_STYLE_SUN_C) {
-        string = "-G";
+        string = chaz_Util_join("", "-G -h lib", basename, ".so.",
+                                major_version, NULL);
     }
     else {
         chaz_Util_die("Don't know how to link a shared library with '%s'",
                       chaz_CC_get_cc());
     }
-    chaz_CFlags_append(flags, string);
-}
 
-void
-chaz_CFlags_set_shared_library_version(chaz_CFlags *flags, chaz_Lib *lib) {
-    if (flags->style == CHAZ_CFLAGS_STYLE_GNU) {
-        int binary_format = chaz_CC_binary_format();
-
-        if (binary_format == CHAZ_CC_BINFMT_MACHO) {
-            const char *version = chaz_Lib_get_version(lib);
-            char *string
-                = chaz_Util_join(" ", "-current_version", version, NULL);
-            chaz_CFlags_append(flags, string);
-            free(string);
-        }
-        else if (binary_format == CHAZ_CC_BINFMT_ELF) {
-            char *soname = chaz_Lib_major_version_filename(lib);
-            char *string = chaz_Util_join("", "-Wl,-soname,", soname, NULL);
-            chaz_CFlags_append(flags, string);
-            free(string);
-            free(soname);
-        }
-    }
-    else if (flags->style == CHAZ_CFLAGS_STYLE_SUN_C) {
-        char *soname = chaz_Lib_major_version_filename(lib);
-        char *string = chaz_Util_join(" ", "-h", soname, NULL);
+    if (string) {
         chaz_CFlags_append(flags, string);
         free(string);
-        free(soname);
     }
 }
 
@@ -333,20 +321,22 @@ chaz_CFlags_add_library_path(chaz_CFlags *flags, const 
char *directory) {
 }
 
 void
-chaz_CFlags_add_library(chaz_CFlags *flags, chaz_Lib *lib) {
+chaz_CFlags_add_shared_lib(chaz_CFlags *flags, const char *dir,
+                           const char *basename, const char *major_version) {
+    int binfmt = chaz_CC_binary_format();
     char *filename;
-    if (flags->style == CHAZ_CFLAGS_STYLE_MSVC) {
-        filename = chaz_Lib_implib_filename(lib);
+    if (binfmt == CHAZ_CC_BINFMT_PE) {
+        filename = chaz_CC_import_lib_filename(dir, basename, major_version);
     }
     else {
-        filename = chaz_Lib_filename(lib);
+        filename = chaz_CC_shared_lib_filename(dir, basename, major_version);
     }
     chaz_CFlags_append(flags, filename);
     free(filename);
 }
 
 void
-chaz_CFlags_add_external_library(chaz_CFlags *flags, const char *library) {
+chaz_CFlags_add_external_lib(chaz_CFlags *flags, const char *library) {
     char *string;
     if (flags->style == CHAZ_CFLAGS_STYLE_MSVC) {
         string = chaz_Util_join("", library, ".lib", NULL);

http://git-wip-us.apache.org/repos/asf/lucy-charmonizer/blob/1ce65627/src/Charmonizer/Core/CFlags.h
----------------------------------------------------------------------
diff --git a/src/Charmonizer/Core/CFlags.h b/src/Charmonizer/Core/CFlags.h
index 901eb45..ec699df 100644
--- a/src/Charmonizer/Core/CFlags.h
+++ b/src/Charmonizer/Core/CFlags.h
@@ -24,8 +24,6 @@
 extern "C" {
 #endif
 
-#include "Charmonizer/Core/Library.h"
-
 #define CHAZ_CFLAGS_STYLE_POSIX  1
 #define CHAZ_CFLAGS_STYLE_GNU    2
 #define CHAZ_CFLAGS_STYLE_MSVC   3
@@ -77,10 +75,9 @@ void
 chaz_CFlags_hide_symbols(chaz_CFlags *flags);
 
 void
-chaz_CFlags_link_shared_library(chaz_CFlags *flags);
-
-void
-chaz_CFlags_set_shared_library_version(chaz_CFlags *flags, chaz_Lib *lib);
+chaz_CFlags_link_shared_library(chaz_CFlags *flags, const char *basename,
+                                const char *version,
+                                const char *major_version);
 
 void
 chaz_CFlags_set_link_output(chaz_CFlags *flags, const char *filename);
@@ -89,10 +86,11 @@ void
 chaz_CFlags_add_library_path(chaz_CFlags *flags, const char *directory);
 
 void
-chaz_CFlags_add_library(chaz_CFlags *flags, chaz_Lib *lib);
+chaz_CFlags_add_shared_lib(chaz_CFlags *flags, const char *dir,
+                           const char *basename, const char *major_version);
 
 void
-chaz_CFlags_add_external_library(chaz_CFlags *flags, const char *library);
+chaz_CFlags_add_external_lib(chaz_CFlags *flags, const char *library);
 
 void
 chaz_CFlags_enable_code_coverage(chaz_CFlags *flags);

http://git-wip-us.apache.org/repos/asf/lucy-charmonizer/blob/1ce65627/src/Charmonizer/Core/Compiler.c
----------------------------------------------------------------------
diff --git a/src/Charmonizer/Core/Compiler.c b/src/Charmonizer/Core/Compiler.c
index dd4fa6c..83177f2 100644
--- a/src/Charmonizer/Core/Compiler.c
+++ b/src/Charmonizer/Core/Compiler.c
@@ -37,6 +37,13 @@ chaz_CC_eval_macro(const char *macro);
 static void
 chaz_CC_detect_known_compilers(void);
 
+/** Build a library filename from its components.
+ */
+static char*
+chaz_CC_build_lib_filename(const char *dir, const char *prefix,
+                           const char *basename, const char *version,
+                           const char *ext);
+
 /* Temporary files. */
 #define CHAZ_CC_TRY_SOURCE_PATH  "_charmonizer_try.c"
 #define CHAZ_CC_TRY_BASENAME     "_charmonizer_try"
@@ -75,7 +82,6 @@ void
 chaz_CC_init(const char *compiler_command, const char *compiler_flags) {
     const char *code = "int main() { return 0; }\n";
     int compile_succeeded = 0;
-    int retval            = -1;
 
     if (chaz_Util_verbosity) { printf("Creating compiler object...\n"); }
 
@@ -566,7 +572,8 @@ chaz_CC_format_archiver_command(const char *target, const 
char *objects) {
         /* TODO: Write `objects` to a temporary file in order to avoid
          * exceeding line length limits. */
         char *out = chaz_Util_join("", "/OUT:", target, NULL);
-        char *command = chaz_Util_join(" ", "lib", "/NOLOGO", out, NULL);
+        char *command = chaz_Util_join(" ", "lib", "/NOLOGO", objects, out,
+                                       NULL);
         free(out);
         return command;
     }
@@ -583,3 +590,85 @@ chaz_CC_format_ranlib_command(const char *target) {
     return chaz_Util_join(" ", "ranlib", target, NULL);
 }
 
+char*
+chaz_CC_shared_lib_filename(const char *dir, const char *basename,
+                            const char *version) {
+    /* Cygwin uses a "cyg" prefix for shared libraries. */
+    const char *prefix = chaz_CC_msvc_version_num()
+                         ? ""
+                         : chaz_CC_is_cygwin() ? "cyg" : "lib";
+    return chaz_CC_build_lib_filename(dir, prefix, basename, version,
+                                      chaz_CC.shared_lib_ext);
+}
+
+char*
+chaz_CC_import_lib_filename(const char *dir, const char *basename,
+                            const char *version) {
+    const char *prefix = chaz_CC_msvc_version_num() ? "" : "lib";
+    return chaz_CC_build_lib_filename(dir, prefix, basename, version,
+                                      chaz_CC.import_lib_ext);
+}
+
+char*
+chaz_CC_export_filename(const char *dir, const char *basename,
+                        const char *version) {
+    /* Only for MSVC. */
+    return chaz_CC_build_lib_filename(dir, "", basename, version, ".exp");
+}
+
+static char*
+chaz_CC_build_lib_filename(const char *dir, const char *prefix,
+                           const char *basename, const char *version,
+                           const char *ext) {
+    char *suffix;
+    char *retval;
+
+    if (version == NULL) {
+        suffix = chaz_Util_strdup(ext);
+    }
+    else {
+        int binary_format = chaz_CC_binary_format();
+
+        if (binary_format == CHAZ_CC_BINFMT_PE) {
+            suffix = chaz_Util_join("", "-", version, ext, NULL);
+        }
+        else if (binary_format == CHAZ_CC_BINFMT_MACHO) {
+            suffix = chaz_Util_join("", ".", version, ext, NULL);
+        }
+        else if (binary_format == CHAZ_CC_BINFMT_ELF) {
+            suffix = chaz_Util_join("", ext, ".", version, NULL);
+        }
+        else {
+            chaz_Util_die("Unsupported binary format");
+            return NULL;
+        }
+    }
+
+    if (dir == NULL || strcmp(dir, ".") == 0) {
+        retval = chaz_Util_join("", prefix, basename, suffix, NULL);
+    }
+    else {
+        const char *dir_sep = chaz_OS_dir_sep();
+        retval = chaz_Util_join("", dir, dir_sep, prefix, basename, suffix,
+                                NULL);
+    }
+
+    free(suffix);
+    return retval;
+}
+
+char*
+chaz_CC_static_lib_filename(const char *dir, const char *basename) {
+    const char *prefix = chaz_CC_msvc_version_num() ? "" : "lib";
+
+    if (dir == NULL || strcmp(dir, ".") == 0) {
+        return chaz_Util_join("", prefix, basename, chaz_CC.static_lib_ext,
+                              NULL);
+    }
+    else {
+        const char *dir_sep = chaz_OS_dir_sep();
+        return chaz_Util_join("", dir, dir_sep, prefix, basename,
+                              chaz_CC.static_lib_ext, NULL);
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/lucy-charmonizer/blob/1ce65627/src/Charmonizer/Core/Compiler.h
----------------------------------------------------------------------
diff --git a/src/Charmonizer/Core/Compiler.h b/src/Charmonizer/Core/Compiler.h
index 6361af7..8190123 100644
--- a/src/Charmonizer/Core/Compiler.h
+++ b/src/Charmonizer/Core/Compiler.h
@@ -169,6 +169,44 @@ chaz_CC_format_archiver_command(const char *target, const 
char *objects);
 char*
 chaz_CC_format_ranlib_command(const char *target);
 
+/** Returns the filename for a shared library.
+ *
+ * @param dir The target directory or NULL for the current directory.
+ * @param basename The name of the library without prefix and extension.
+ * @param version The library version.
+ */
+char*
+chaz_CC_shared_lib_filename(const char *dir, const char *basename,
+                            const char *version);
+
+/** Returns the filename for an import library.
+ *
+ * @param dir The target directory or NULL for the current directory.
+ * @param basename The name of the library without prefix and extension.
+ * @param version The library version.
+ */
+char*
+chaz_CC_import_lib_filename(const char *dir, const char *basename,
+                            const char *version);
+
+/** Returns the filename for an MSVC export file.
+ *
+ * @param dir The target directory or NULL for the current directory.
+ * @param basename The name of the library without prefix and extension.
+ * @param version The library version.
+ */
+char*
+chaz_CC_export_filename(const char *dir, const char *basename,
+                        const char *version);
+
+/** Returns the filename for a static library.
+ *
+ * @param dir The target directory or NULL for the current directory.
+ * @param basename The name of the library without prefix and extension.
+ */
+char*
+chaz_CC_static_lib_filename(const char *dir, const char *basename);
+
 #ifdef __cplusplus
 }
 #endif

http://git-wip-us.apache.org/repos/asf/lucy-charmonizer/blob/1ce65627/src/Charmonizer/Core/Library.c
----------------------------------------------------------------------
diff --git a/src/Charmonizer/Core/Library.c b/src/Charmonizer/Core/Library.c
deleted file mode 100644
index d1e0cb6..0000000
--- a/src/Charmonizer/Core/Library.c
+++ /dev/null
@@ -1,174 +0,0 @@
-/* Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <string.h>
-#include <stdlib.h>
-#include "Charmonizer/Core/Library.h"
-#include "Charmonizer/Core/Compiler.h"
-#include "Charmonizer/Core/Util.h"
-#include "Charmonizer/Core/OperatingSystem.h"
-
-struct chaz_Lib {
-    char *name;
-    char *version;
-    char *major_version;
-    int   is_static;
-    int   is_shared;
-};
-
-static char*
-S_build_filename(chaz_Lib *lib, const char *version, const char *ext);
-
-static const char*
-S_get_prefix(chaz_Lib *lib);
-
-chaz_Lib*
-chaz_Lib_new_shared(const char *name, const char *version,
-                    const char *major_version) {
-    chaz_Lib *lib = (chaz_Lib*)malloc(sizeof(chaz_Lib));
-    lib->name          = chaz_Util_strdup(name);
-    lib->version       = chaz_Util_strdup(version);
-    lib->major_version = chaz_Util_strdup(major_version);
-    lib->is_shared = 1;
-    lib->is_static = 0;
-    return lib;
-}
-
-chaz_Lib*
-chaz_Lib_new_static(const char *name) {
-    chaz_Lib *lib = (chaz_Lib*)malloc(sizeof(chaz_Lib));
-    lib->name          = chaz_Util_strdup(name);
-    lib->version       = NULL;
-    lib->major_version = NULL;
-    lib->is_shared = 0;
-    lib->is_static = 1;
-    return lib;
-}
-
-void
-chaz_Lib_destroy(chaz_Lib *lib) {
-    free(lib->name);
-    free(lib->version);
-    free(lib->major_version);
-    free(lib);
-}
-
-const char*
-chaz_Lib_get_name(chaz_Lib *lib) {
-    return lib->name;
-}
-
-const char*
-chaz_Lib_get_version(chaz_Lib *lib) {
-    return lib->version;
-}
-
-const char*
-chaz_Lib_get_major_version(chaz_Lib *lib) {
-    return lib->major_version;
-}
-
-int
-chaz_Lib_is_shared (chaz_Lib *lib) {
-    return lib->is_shared;
-}
-
-int
-chaz_Lib_is_static (chaz_Lib *lib) {
-    return lib->is_static;
-}
-
-char*
-chaz_Lib_filename(chaz_Lib *lib) {
-    if (lib->is_static) {
-        return chaz_Lib_no_version_filename(lib);
-    }
-    else {
-        const char *ext = chaz_CC_shared_lib_ext();
-        if (chaz_CC_binary_format() == CHAZ_CC_BINFMT_PE) {
-            return S_build_filename(lib, lib->major_version, ext);
-        }
-        else {
-            return S_build_filename(lib, lib->version, ext);
-        }
-    }
-}
-
-char*
-chaz_Lib_major_version_filename(chaz_Lib *lib) {
-    if (lib->is_static) {
-        return chaz_Lib_no_version_filename(lib);
-    }
-    else {
-        const char *ext = chaz_CC_shared_lib_ext();
-        return S_build_filename(lib, lib->major_version, ext);
-    }
-}
-
-char*
-chaz_Lib_no_version_filename(chaz_Lib *lib) {
-    const char *prefix = S_get_prefix(lib);
-    const char *ext = lib->is_shared
-                      ? chaz_CC_shared_lib_ext()
-                      : chaz_CC_static_lib_ext();
-    return chaz_Util_join("", prefix, lib->name, ext, NULL);
-}
-
-char*
-chaz_Lib_implib_filename(chaz_Lib *lib) {
-    const char *ext = chaz_CC_import_lib_ext();
-    return S_build_filename(lib, lib->major_version, ext);
-}
-
-char*
-chaz_Lib_export_filename(chaz_Lib *lib) {
-    return S_build_filename(lib, lib->major_version, ".exp");
-}
-
-static char*
-S_build_filename(chaz_Lib *lib, const char *version, const char *ext) {
-    const char *prefix = S_get_prefix(lib);
-    int binary_format = chaz_CC_binary_format();
-
-    if (binary_format == CHAZ_CC_BINFMT_PE) {
-        return chaz_Util_join("", prefix, lib->name, "-", version, ext, NULL);
-    }
-    else if (binary_format == CHAZ_CC_BINFMT_MACHO) {
-        return chaz_Util_join("", prefix, lib->name, ".", version, ext, NULL);
-    }
-    else if (binary_format == CHAZ_CC_BINFMT_ELF) {
-        return chaz_Util_join("", prefix, lib->name, ext, ".", version, NULL);
-    }
-    else {
-        chaz_Util_die("Unsupported binary format");
-        return NULL;
-    }
-}
-
-static const char*
-S_get_prefix(chaz_Lib *lib) {
-    if (chaz_CC_msvc_version_num()) {
-        return "";
-    }
-    else if (chaz_CC_is_cygwin()) {
-        return lib->is_static ? "lib" : "cyg";
-    }
-    else {
-        return "lib";
-    }
-}
-
-

http://git-wip-us.apache.org/repos/asf/lucy-charmonizer/blob/1ce65627/src/Charmonizer/Core/Library.h
----------------------------------------------------------------------
diff --git a/src/Charmonizer/Core/Library.h b/src/Charmonizer/Core/Library.h
deleted file mode 100644
index 80fff83..0000000
--- a/src/Charmonizer/Core/Library.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/* Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* Charmonizer/Core/Library.h
- */
-
-#ifndef H_CHAZ_LIB
-#define H_CHAZ_LIB
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct chaz_Lib chaz_Lib;
-
-chaz_Lib*
-chaz_Lib_new_shared(const char *name, const char *version,
-                    const char *major_version);
-
-chaz_Lib*
-chaz_Lib_new_static(const char *name);
-
-void
-chaz_Lib_destroy(chaz_Lib *flags);
-
-const char*
-chaz_Lib_get_name(chaz_Lib *lib);
-
-const char*
-chaz_Lib_get_version(chaz_Lib *lib);
-
-const char*
-chaz_Lib_get_major_version(chaz_Lib *lib);
-
-int
-chaz_Lib_is_shared(chaz_Lib *lib);
-
-int
-chaz_Lib_is_static(chaz_Lib *lib);
-
-char*
-chaz_Lib_filename(chaz_Lib *lib);
-
-char*
-chaz_Lib_major_version_filename(chaz_Lib *lib);
-
-char*
-chaz_Lib_no_version_filename(chaz_Lib *lib);
-
-char*
-chaz_Lib_implib_filename(chaz_Lib *lib);
-
-char*
-chaz_Lib_export_filename(chaz_Lib *lib);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* H_CHAZ_LIB */
-
-

http://git-wip-us.apache.org/repos/asf/lucy-charmonizer/blob/1ce65627/src/Charmonizer/Core/Make.c
----------------------------------------------------------------------
diff --git a/src/Charmonizer/Core/Make.c b/src/Charmonizer/Core/Make.c
index 8e8699b..23350f8 100644
--- a/src/Charmonizer/Core/Make.c
+++ b/src/Charmonizer/Core/Make.c
@@ -18,10 +18,15 @@
 #include <stdlib.h>
 #include <string.h>
 #include "Charmonizer/Core/Make.h"
+#include "Charmonizer/Core/CFlags.h"
 #include "Charmonizer/Core/Compiler.h"
 #include "Charmonizer/Core/OperatingSystem.h"
 #include "Charmonizer/Core/Util.h"
 
+#define CHAZ_MAKEBINARY_EXE         1
+#define CHAZ_MAKEBINARY_STATIC_LIB  2
+#define CHAZ_MAKEBINARY_SHARED_LIB  3
+
 struct chaz_MakeVar {
     char   *name;
     char   *value;
@@ -34,13 +39,34 @@ struct chaz_MakeRule {
     char *commands;
 };
 
+struct chaz_MakeBinary {
+    int             type;
+    char           *target_dir;
+    char           *basename;
+    char           *version;
+    char           *major_version;
+    char          **sources;  /* List of all sources. */
+    size_t          num_sources;
+    char          **single_sources;  /* Only sources from add_src_file. */
+    size_t          num_single_sources;
+    char          **dirs;
+    size_t          num_dirs;
+    chaz_MakeVar   *obj_var;  /* Owned by MakeFile. */
+    char           *dollar_var;
+    chaz_MakeRule  *rule;  /* Not added to MakeFile, owned by MakeBinary. */
+    chaz_CFlags    *compile_flags;
+    chaz_CFlags    *link_flags;
+};
+
 struct chaz_MakeFile {
-    chaz_MakeVar  **vars;
-    size_t          num_vars;
-    chaz_MakeRule **rules;
-    size_t          num_rules;
-    chaz_MakeRule  *clean;
-    chaz_MakeRule  *distclean;
+    chaz_MakeVar    **vars;
+    size_t            num_vars;
+    chaz_MakeRule   **rules;
+    size_t            num_rules;
+    chaz_MakeRule    *clean;
+    chaz_MakeRule    *distclean;
+    chaz_MakeBinary **binaries;
+    size_t            num_binaries;
 };
 
 /* Static vars. */
@@ -69,6 +95,31 @@ chaz_Make_detect(const char *make1, ...);
 static int
 chaz_Make_audition(const char *make);
 
+static void
+chaz_MakeFile_finish_exe(chaz_MakeFile *self, chaz_MakeBinary *binary);
+
+static void
+chaz_MakeFile_finish_shared_lib(chaz_MakeFile *self, chaz_MakeBinary *binary);
+
+static void
+chaz_MakeFile_finish_static_lib(chaz_MakeFile *self, chaz_MakeBinary *binary);
+
+static chaz_MakeBinary*
+chaz_MakeFile_add_binary(chaz_MakeFile *self, int type, const char *dir,
+                         const char *basename, const char *target);
+
+static void
+chaz_MakeFile_write_binary_rules(chaz_MakeFile *self, chaz_MakeBinary *binary,
+                                 FILE *out);
+
+static void
+chaz_MakeFile_write_object_rules(char **sources, const char *command,
+                                 FILE *out);
+
+static void
+chaz_MakeFile_write_pattern_rules(char **dirs, const char *command,
+                                  FILE *out);
+
 static chaz_MakeRule*
 S_new_rule(const char *target, const char *prereq);
 
@@ -78,19 +129,48 @@ S_destroy_rule(chaz_MakeRule *rule);
 static void
 S_write_rule(chaz_MakeRule *rule, FILE *out);
 
+static void
+chaz_MakeBinary_destroy(chaz_MakeBinary *self);
+
+static void
+chaz_MakeBinary_list_files_callback(const char *dir, char *file,
+                                    void *context);
+static void
+chaz_MakeBinary_do_add_src_file(chaz_MakeBinary *self, const char *path);
+
+/** Return the path to the object file for a source file.
+ *
+ * @param path The path to the source file.
+ */
+static char*
+chaz_MakeBinary_obj_path(const char *src_path);
+
 void
 chaz_Make_init(const char *make_command) {
     chaz_Make.shell_type = chaz_OS_shell_type();
 
     if (make_command) {
         if (!chaz_Make_detect(make_command, NULL)) {
-            chaz_Util_warn("Make utility '%s' doesn't appear to work");
+            chaz_Util_warn("Make utility '%s' doesn't appear to work",
+                           make_command);
         }
     }
     else {
-        if (!chaz_Make_detect("make", "gmake", "nmake", "dmake",
-                              "mingw32-make", "mingw64-make", NULL)
-           ) {
+        int succeeded = 0;
+
+        /* mingw32-make seems to try to run commands under both cmd.exe
+         * and sh.exe. Not sure about dmake.
+         */
+        if (chaz_Make.shell_type == CHAZ_OS_POSIX) {
+            succeeded = chaz_Make_detect("make", "gmake", "dmake",
+                                         "mingw32-make", NULL);
+        }
+        else if (chaz_Make.shell_type = CHAZ_OS_CMD_EXE) {
+            succeeded = chaz_Make_detect("nmake", "dmake", "mingw32-make",
+                                         NULL);
+        }
+
+        if (!succeeded) {
             chaz_Util_warn("No working make utility found");
         }
         else if (chaz_Util_verbosity) {
@@ -119,7 +199,7 @@ chaz_Make_detect(const char *make1, ...) {
     va_list args;
     const char *candidate;
     int found = 0;
-    const char makefile_content[] = "foo:\n\techo foo\\^bar\n";
+    const char makefile_content[] = "foo:\n\t@echo 643490c943525d19\n";
     chaz_Util_write_file("_charm_Makefile", makefile_content);
 
     /* Audition candidates. */
@@ -145,15 +225,8 @@ chaz_Make_audition(const char *make) {
     if (chaz_Util_can_open_file("_charm_foo")) {
         size_t len;
         char *content = chaz_Util_slurp_file("_charm_foo", &len);
-        if (NULL != strstr(content, "foo\\bar")) {
-            if (chaz_Make.shell_type == CHAZ_OS_CMD_EXE) {
-                succeeded = 1;
-            }
-        }
-        else if (NULL != strstr(content, "foo^bar")) {
-            if (chaz_Make.shell_type == CHAZ_OS_POSIX) {
-                succeeded = 1;
-            }
+        if (content != NULL && strstr(content, "643490c943525d19") != NULL) {
+            succeeded = 1;
         }
         free(content);
     }
@@ -169,51 +242,52 @@ chaz_Make_audition(const char *make) {
 
 chaz_MakeFile*
 chaz_MakeFile_new() {
-    chaz_MakeFile *makefile = (chaz_MakeFile*)malloc(sizeof(chaz_MakeFile));
+    chaz_MakeFile *self = (chaz_MakeFile*)calloc(1, sizeof(chaz_MakeFile));
     const char    *exe_ext  = chaz_CC_exe_ext();
     const char    *obj_ext  = chaz_CC_obj_ext();
     char *generated;
 
-    makefile->vars = (chaz_MakeVar**)malloc(sizeof(chaz_MakeVar*));
-    makefile->vars[0] = NULL;
-    makefile->num_vars = 0;
-
-    makefile->rules = (chaz_MakeRule**)malloc(sizeof(chaz_MakeRule*));
-    makefile->rules[0] = NULL;
-    makefile->num_rules = 0;
+    self->vars     = (chaz_MakeVar**)calloc(1, sizeof(chaz_MakeVar*));
+    self->rules    = (chaz_MakeRule**)calloc(1, sizeof(chaz_MakeRule*));
+    self->binaries = (chaz_MakeBinary**)calloc(1, sizeof(chaz_MakeBinary*));
 
-    makefile->clean     = S_new_rule("clean", NULL);
-    makefile->distclean = S_new_rule("distclean", "clean");
+    self->clean     = S_new_rule("clean", NULL);
+    self->distclean = S_new_rule("distclean", "clean");
 
     generated = chaz_Util_join("", "charmonizer", exe_ext, " charmonizer",
                                obj_ext, " charmony.h Makefile", NULL);
-    chaz_MakeRule_add_rm_command(makefile->distclean, generated);
+    chaz_MakeRule_add_rm_command(self->distclean, generated);
 
     free(generated);
-    return makefile;
+    return self;
 }
 
 void
-chaz_MakeFile_destroy(chaz_MakeFile *makefile) {
+chaz_MakeFile_destroy(chaz_MakeFile *self) {
     size_t i;
 
-    for (i = 0; makefile->vars[i]; i++) {
-        chaz_MakeVar *var = makefile->vars[i];
+    for (i = 0; self->vars[i]; i++) {
+        chaz_MakeVar *var = self->vars[i];
         free(var->name);
         free(var->value);
         free(var);
     }
-    free(makefile->vars);
+    free(self->vars);
 
-    for (i = 0; makefile->rules[i]; i++) {
-        S_destroy_rule(makefile->rules[i]);
+    for (i = 0; self->rules[i]; i++) {
+        S_destroy_rule(self->rules[i]);
+    }
+    free(self->rules);
+
+    for (i = 0; self->binaries[i]; i++) {
+        chaz_MakeBinary_destroy(self->binaries[i]);
     }
-    free(makefile->rules);
+    free(self->binaries);
 
-    S_destroy_rule(makefile->clean);
-    S_destroy_rule(makefile->distclean);
+    S_destroy_rule(self->clean);
+    S_destroy_rule(self->distclean);
 
-    free(makefile);
+    free(self);
 }
 
 chaz_MakeVar*
@@ -266,196 +340,249 @@ chaz_MakeFile_distclean_rule(chaz_MakeFile *makefile) {
     return makefile->distclean;
 }
 
-chaz_MakeRule*
-chaz_MakeFile_add_exe(chaz_MakeFile *makefile, const char *exe,
-                      const char *sources, chaz_CFlags *link_flags) {
-    chaz_CFlags   *local_flags  = chaz_CC_new_cflags();
-    const char    *link         = chaz_CC_link_command();
-    const char    *link_flags_string = "";
-    const char    *local_flags_string;
-    chaz_MakeRule *rule;
-    char          *command;
-
-    rule = chaz_MakeFile_add_rule(makefile, exe, sources);
+chaz_MakeBinary*
+chaz_MakeFile_add_exe(chaz_MakeFile *self, const char *dir,
+                      const char *basename) {
+    const char *exe_ext = chaz_CC_exe_ext();
+    char *target;
+    chaz_MakeBinary *binary;
 
-    if (link_flags) {
-        link_flags_string = chaz_CFlags_get_string(link_flags);
+    if (dir == NULL || strcmp(dir, ".") == 0) {
+        target = chaz_Util_join("", basename, exe_ext, NULL);
     }
-    if (chaz_CC_msvc_version_num()) {
-        chaz_CFlags_append(local_flags, "/nologo");
+    else {
+        const char *dir_sep = chaz_OS_dir_sep();
+        target = chaz_Util_join("", dir, dir_sep, basename, exe_ext, NULL);
     }
-    chaz_CFlags_set_link_output(local_flags, exe);
-    local_flags_string = chaz_CFlags_get_string(local_flags);
-    command = chaz_Util_join(" ", link, sources, link_flags_string,
-                             local_flags_string, NULL);
-    chaz_MakeRule_add_command(rule, command);
 
-    chaz_MakeRule_add_rm_command(makefile->clean, exe);
+    binary = chaz_MakeFile_add_binary(self, CHAZ_MAKEBINARY_EXE, dir, basename,
+                                      target);
 
-    chaz_CFlags_destroy(local_flags);
-    free(command);
-    return rule;
+    free(target);
+    return binary;
 }
 
-chaz_MakeRule*
-chaz_MakeFile_add_compiled_exe(chaz_MakeFile *makefile, const char *exe,
-                               const char *sources, chaz_CFlags *cflags) {
-    chaz_CFlags   *local_flags   = chaz_CC_new_cflags();
-    const char    *cc            = chaz_CC_get_cc();
-    const char    *cflags_string = "";
-    const char    *local_flags_string;
-    chaz_MakeRule *rule;
-    char          *command;
+void
+chaz_MakeFile_finish_exe(chaz_MakeFile *self, chaz_MakeBinary *binary) {
+    const char *link = chaz_CC_link_command();
+    const char *link_flags_string;
+    char *command;
+
+    (void)self;
+
+    /* This is destructive but shouldn't be a problem since a Makefile
+     * is only written once.
+     */
+    chaz_CFlags_set_link_output(binary->link_flags, "$@");
+    link_flags_string = chaz_CFlags_get_string(binary->link_flags);
 
-    rule = chaz_MakeFile_add_rule(makefile, exe, sources);
+    /* Objects in dollar var must come before flags since flags may
+     * contain libraries.
+     */
+    command = chaz_Util_join(" ", link, binary->dollar_var, link_flags_string,
+                             NULL);
+    chaz_MakeRule_add_command(binary->rule, command);
+    free(command);
+}
 
-    if (cflags) {
-        cflags_string = chaz_CFlags_get_string(cflags);
+chaz_MakeBinary*
+chaz_MakeFile_add_shared_lib(chaz_MakeFile *self, const char *dir,
+                             const char *basename, const char *version,
+                             const char *major_version) {
+    int binary_format = chaz_CC_binary_format();
+    char *target;
+    chaz_MakeBinary *binary;
+
+    if (binary_format == CHAZ_CC_BINFMT_PE) {
+        target = chaz_CC_shared_lib_filename(dir, basename, major_version);
     }
-    if (chaz_CC_msvc_version_num()) {
-        chaz_CFlags_append(local_flags, "/nologo");
+    else {
+        target = chaz_CC_shared_lib_filename(dir, basename, version);
     }
-    chaz_CFlags_set_output_exe(local_flags, exe);
-    local_flags_string = chaz_CFlags_get_string(local_flags);
-    command = chaz_Util_join(" ", cc, sources, cflags_string,
-                             local_flags_string, NULL);
-    chaz_MakeRule_add_command(rule, command);
 
-    chaz_MakeRule_add_rm_command(makefile->clean, exe);
-    /* TODO: Clean .obj file on Windows. */
+    binary = chaz_MakeFile_add_binary(self, CHAZ_MAKEBINARY_SHARED_LIB, dir,
+                                      basename, target);
+    binary->version       = chaz_Util_strdup(version);
+    binary->major_version = chaz_Util_strdup(major_version);
 
-    chaz_CFlags_destroy(local_flags);
-    free(command);
-    return rule;
+    chaz_CFlags_compile_shared_library(binary->compile_flags);
+    chaz_CFlags_link_shared_library(binary->link_flags, basename, version,
+                                    major_version);
+
+    free(target);
+    return binary;
 }
 
-chaz_MakeRule*
-chaz_MakeFile_add_shared_lib(chaz_MakeFile *makefile, chaz_Lib *lib,
-                             const char *sources, chaz_CFlags *link_flags) {
-    chaz_CFlags *local_flags = chaz_CC_new_cflags();
+void
+chaz_MakeFile_finish_shared_lib(chaz_MakeFile *self, chaz_MakeBinary *binary) {
     const char *link = chaz_CC_link_command();
-    const char *link_flags_string = "";
-    const char *local_flags_string;
+    const char *link_flags_string;
     int binfmt = chaz_CC_binary_format();
-    chaz_MakeRule *rule;
-    char *filename;
+    char *no_v_name
+        = chaz_CC_shared_lib_filename(binary->target_dir, binary->basename,
+                                      NULL);
+    char *major_v_name
+        = chaz_CC_shared_lib_filename(binary->target_dir, binary->basename,
+                                      binary->major_version);
     char *command;
 
-    filename = chaz_Lib_filename(lib);
-    rule = chaz_MakeFile_add_rule(makefile, filename, sources);
-
-    if (link_flags) {
-        link_flags_string = chaz_CFlags_get_string(link_flags);
-    }
-
-    if (chaz_CC_msvc_version_num()) {
-        chaz_CFlags_append(local_flags, "/nologo");
-    }
-    chaz_CFlags_link_shared_library(local_flags);
     if (binfmt == CHAZ_CC_BINFMT_MACHO) {
-        /* Set temporary install name with full path on Darwin. */
         const char *dir_sep = chaz_OS_dir_sep();
-        char *major_v_name = chaz_Lib_major_version_filename(lib);
-        char *install_name = chaz_Util_join("", "-install_name $(CURDIR)",
-                                            dir_sep, major_v_name, NULL);
-        chaz_CFlags_append(local_flags, install_name);
-        free(major_v_name);
+        char *install_name;
+
+        /* Set temporary install name with full path on Darwin. */
+        install_name = chaz_Util_join("", "-install_name $(CURDIR)", dir_sep,
+                                      major_v_name, NULL);
+        chaz_CFlags_append(binary->link_flags, install_name);
         free(install_name);
     }
-    chaz_CFlags_set_shared_library_version(local_flags, lib);
-    chaz_CFlags_set_link_output(local_flags, filename);
-    local_flags_string = chaz_CFlags_get_string(local_flags);
 
-    command = chaz_Util_join(" ", link, sources, link_flags_string,
-                             local_flags_string, NULL);
-    chaz_MakeRule_add_command(rule, command);
-    free(command);
+    chaz_CFlags_set_link_output(binary->link_flags, "$@");
+    link_flags_string = chaz_CFlags_get_string(binary->link_flags);
 
-    chaz_MakeRule_add_rm_command(makefile->clean, filename);
+    command = chaz_Util_join(" ", link, binary->dollar_var, link_flags_string,
+                             NULL);
+    chaz_MakeRule_add_command(binary->rule, command);
+    free(command);
 
     /* Add symlinks. */
     if (binfmt == CHAZ_CC_BINFMT_ELF || binfmt == CHAZ_CC_BINFMT_MACHO) {
-        char *major_v_name = chaz_Lib_major_version_filename(lib);
-        char *no_v_name    = chaz_Lib_no_version_filename(lib);
-
-        command = chaz_Util_join(" ", "ln -sf", filename, major_v_name, NULL);
-        chaz_MakeRule_add_command(rule, command);
+        command = chaz_Util_join(" ", "ln -sf", binary->rule->targets,
+                                 major_v_name, NULL);
+        chaz_MakeRule_add_command(binary->rule, command);
         free(command);
 
         if (binfmt == CHAZ_CC_BINFMT_MACHO) {
-            command = chaz_Util_join(" ", "ln -sf", filename, no_v_name,
-                                     NULL);
+            command = chaz_Util_join(" ", "ln -sf", binary->rule->targets,
+                                     no_v_name, NULL);
         }
         else {
             command = chaz_Util_join(" ", "ln -sf", major_v_name, no_v_name,
                                      NULL);
         }
-        chaz_MakeRule_add_command(rule, command);
+        chaz_MakeRule_add_command(binary->rule, command);
         free(command);
 
-        chaz_MakeRule_add_rm_command(makefile->clean, major_v_name);
-        chaz_MakeRule_add_rm_command(makefile->clean, no_v_name);
+        chaz_MakeRule_add_rm_command(self->clean, major_v_name);
+        chaz_MakeRule_add_rm_command(self->clean, no_v_name);
+    }
 
-        free(major_v_name);
-        free(no_v_name);
+    if (binfmt == CHAZ_CC_BINFMT_PE) {
+        /* Remove import library. */
+        char *filename
+            = chaz_CC_import_lib_filename(binary->target_dir, binary->basename,
+                                          binary->major_version);
+        chaz_MakeRule_add_rm_command(self->clean, filename);
+        free(filename);
     }
 
     if (chaz_CC_msvc_version_num()) {
-        /* Remove import library and export file under MSVC. */
-        char *lib_filename = chaz_Lib_implib_filename(lib);
-        char *exp_filename = chaz_Lib_export_filename(lib);
-        chaz_MakeRule_add_rm_command(makefile->clean, lib_filename);
-        chaz_MakeRule_add_rm_command(makefile->clean, exp_filename);
-        free(lib_filename);
-        free(exp_filename);
+        /* Remove export file. */
+        char *filename
+            = chaz_CC_export_filename(binary->target_dir, binary->basename,
+                                      binary->major_version);
+        chaz_MakeRule_add_rm_command(self->clean, filename);
+        free(filename);
     }
 
-    chaz_CFlags_destroy(local_flags);
-    free(filename);
-    return rule;
+    free(major_v_name);
+    free(no_v_name);
 }
 
-chaz_MakeRule*
-chaz_MakeFile_add_static_lib(chaz_MakeFile *makefile, chaz_Lib *lib,
-                             const char *objects) {
-    chaz_MakeRule *rule;
-    char          *filename;
-    char          *command;
-
-    filename = chaz_Lib_filename(lib);
-    rule = chaz_MakeFile_add_rule(makefile, filename, objects);
-    command = chaz_CC_format_archiver_command(filename, objects);
-    chaz_MakeRule_add_command(rule, command);
+chaz_MakeBinary*
+chaz_MakeFile_add_static_lib(chaz_MakeFile *self, const char *dir,
+                             const char *basename) {
+    char *target = chaz_CC_static_lib_filename(dir, basename);
+    chaz_MakeBinary *binary
+        = chaz_MakeFile_add_binary(self, CHAZ_MAKEBINARY_STATIC_LIB, dir,
+                                   basename, target);
+
+    free(target);
+    return binary;
+}
+
+static void
+chaz_MakeFile_finish_static_lib(chaz_MakeFile *self, chaz_MakeBinary *binary) {
+    char *command;
+
+    (void)self;
+
+    command = chaz_CC_format_archiver_command("$@", binary->dollar_var);
+    chaz_MakeRule_add_command(binary->rule, command);
     free(command);
-    command = chaz_CC_format_ranlib_command(filename);
+
+    command = chaz_CC_format_ranlib_command("$@");
     if (command) {
-        chaz_MakeRule_add_command(rule, command);
+        chaz_MakeRule_add_command(binary->rule, command);
         free(command);
     }
-    chaz_MakeRule_add_rm_command(makefile->clean, filename);
-
-    free(filename);
-    return rule;
 }
 
-chaz_MakeRule*
-chaz_MakeFile_add_lemon_exe(chaz_MakeFile *makefile, const char *dir) {
-    chaz_CFlags   *cflags = chaz_CC_new_cflags();
-    chaz_MakeRule *rule;
-    const char *dir_sep = chaz_OS_dir_sep();
-    const char *exe_ext = chaz_CC_exe_ext();
-    char *lemon_exe = chaz_Util_join("", dir, dir_sep, "lemon", exe_ext, NULL);
-    char *lemon_c   = chaz_Util_join(dir_sep, dir, "lemon.c", NULL);
+static chaz_MakeBinary*
+chaz_MakeFile_add_binary(chaz_MakeFile *self, int type, const char *dir,
+                         const char *basename, const char *target) {
+    chaz_MakeBinary *binary
+        = (chaz_MakeBinary*)calloc(1, sizeof(chaz_MakeBinary));
+    const char *suffix;
+    char *uc_basename = chaz_Util_strdup(basename);
+    char *binary_var_name;
+    char *obj_var_name;
+    char *dollar_var;
+    size_t i;
+    size_t num_binaries;
+    size_t alloc_size;
+    chaz_MakeBinary **binaries;
+
+    switch (type) {
+        case CHAZ_MAKEBINARY_EXE:        suffix = "EXE";        break;
+        case CHAZ_MAKEBINARY_STATIC_LIB: suffix = "STATIC_LIB"; break;
+        case CHAZ_MAKEBINARY_SHARED_LIB: suffix = "SHARED_LIB"; break;
+        default:
+            chaz_Util_die("Unknown binary type %d", type);
+            return NULL;
+    }
 
-    chaz_CFlags_enable_optimization(cflags);
-    chaz_MakeFile_add_var(makefile, "LEMON_EXE", lemon_exe);
-    rule = chaz_MakeFile_add_compiled_exe(makefile, "$(LEMON_EXE)", lemon_c,
-                                          cflags);
+    for (i = 0; uc_basename[i] != '\0'; i++) {
+        uc_basename[i] = toupper((unsigned char)uc_basename[i]);
+    }
 
-    chaz_CFlags_destroy(cflags);
-    free(lemon_c);
-    free(lemon_exe);
-    return rule;
+    binary_var_name = chaz_Util_join("_", uc_basename, suffix, NULL);
+    obj_var_name    = chaz_Util_join("_", uc_basename, suffix, "OBJS", NULL);
+    dollar_var      = chaz_Util_join("", "$(", obj_var_name, ")", NULL);
+
+    chaz_MakeFile_add_var(self, binary_var_name, target);
+
+    binary->type           = type;
+    binary->target_dir     = dir ? chaz_Util_strdup(dir) : NULL;
+    binary->basename       = chaz_Util_strdup(basename);
+    binary->obj_var        = chaz_MakeFile_add_var(self, obj_var_name, NULL);
+    binary->dollar_var     = dollar_var;
+    binary->rule           = S_new_rule(target, dollar_var);
+    binary->sources        = (char**)calloc(1, sizeof(char*));
+    binary->single_sources = (char**)calloc(1, sizeof(char*));
+    binary->dirs           = (char**)calloc(1, sizeof(char*));
+    binary->compile_flags  = chaz_CC_new_cflags();
+    binary->link_flags     = chaz_CC_new_cflags();
+
+    num_binaries = self->num_binaries;
+    alloc_size   = (num_binaries + 2) * sizeof(chaz_MakeBinary*);
+    binaries     = (chaz_MakeBinary**)realloc(self->binaries, alloc_size);
+    binaries[num_binaries]   = binary;
+    binaries[num_binaries+1] = NULL;
+    self->binaries     = binaries;
+    self->num_binaries = num_binaries + 1;
+
+    free(uc_basename);
+    free(obj_var_name);
+    free(binary_var_name);
+    return binary;
+}
+
+chaz_MakeBinary*
+chaz_MakeFile_add_lemon_exe(chaz_MakeFile *makefile, const char *dir) {
+    chaz_MakeBinary *exe = chaz_MakeFile_add_exe(makefile, dir, "lemon");
+    chaz_MakeBinary_add_src_file(exe, dir, "lemon.c");
+    return exe;
 }
 
 chaz_MakeRule*
@@ -482,49 +609,6 @@ chaz_MakeFile_add_lemon_grammar(chaz_MakeFile *makefile,
     return rule;
 }
 
-chaz_MakeRule*
-chaz_MakeFile_override_cflags(chaz_MakeFile *makefile, const char *obj,
-                              chaz_CFlags *cflags) {
-    const char *obj_ext       = chaz_CC_obj_ext();
-    const char *cflags_string = chaz_CFlags_get_string(cflags);
-    size_t obj_ext_len = strlen(obj_ext);
-    size_t obj_len     = strlen(obj);
-    size_t base_len;
-    char *src;
-    char *command;
-    chaz_MakeRule *rule;
-
-    if (obj_len <= obj_ext_len) {
-       chaz_Util_die("Invalid object file: %s", obj);
-    }
-
-    base_len = obj_len - obj_ext_len;
-
-    if (strcmp(obj + base_len, obj_ext) != 0) {
-       chaz_Util_die("Invalid object file: %s", obj);
-    }
-
-    src = malloc(base_len + sizeof(".c"));
-    memcpy(src, obj, base_len);
-    memcpy(src + base_len, ".c", sizeof(".c"));
-
-    rule = chaz_MakeFile_add_rule(makefile, obj, src);
-    if (chaz_CC_msvc_version_num()) {
-        command = chaz_Util_join(" ", "$(CC) /nologo", cflags_string, "/c",
-                                 src, "/Fo$@", NULL);
-    }
-    else {
-        command = chaz_Util_join(" ", "$(CC)", cflags_string, "-c", src,
-                                 "-o $@", NULL);
-    }
-    chaz_MakeRule_add_command(rule, command);
-
-    free(command);
-    free(src);
-
-    return rule;
-}
-
 void
 chaz_MakeFile_write(chaz_MakeFile *makefile) {
     FILE   *out;
@@ -545,6 +629,10 @@ chaz_MakeFile_write(chaz_MakeFile *makefile) {
         S_write_rule(makefile->rules[i], out);
     }
 
+    for (i = 0; makefile->binaries[i]; i++) {
+        chaz_MakeFile_write_binary_rules(makefile, makefile->binaries[i], out);
+    }
+
     S_write_rule(makefile->clean, out);
     S_write_rule(makefile->distclean, out);
 
@@ -561,6 +649,122 @@ chaz_MakeFile_write(chaz_MakeFile *makefile) {
     fclose(out);
 }
 
+static void
+chaz_MakeFile_write_binary_rules(chaz_MakeFile *self, chaz_MakeBinary *binary,
+                                 FILE *out) {
+    const char *cflags;
+
+    if (chaz_CC_msvc_version_num()) {
+        chaz_CFlags_append(binary->link_flags, "/nologo");
+    }
+
+    switch (binary->type) {
+        case CHAZ_MAKEBINARY_EXE:
+            chaz_MakeFile_finish_exe(self, binary);
+            break;
+        case CHAZ_MAKEBINARY_STATIC_LIB:
+            chaz_MakeFile_finish_static_lib(self, binary);
+            break;
+        case CHAZ_MAKEBINARY_SHARED_LIB:
+            chaz_MakeFile_finish_shared_lib(self, binary);
+            break;
+        default:
+            chaz_Util_die("Invalid binary type: %d", binary->type);
+            return;
+    }
+
+    chaz_MakeRule_add_rm_command(self->clean, binary->rule->targets);
+    chaz_MakeRule_add_rm_command(self->clean, binary->dollar_var);
+
+    S_write_rule(binary->rule, out);
+
+    cflags = chaz_CFlags_get_string(binary->compile_flags);
+
+    /* Write rules to compile with custom flags. */
+    if (cflags[0] != '\0') {
+        if (chaz_Make.shell_type == CHAZ_OS_CMD_EXE) {
+            /* Write a rule for each object file. This is needed for nmake
+             * which doesn't support pattern rules but also for mingw32-make
+             * which has problems with pattern rules and backslash directory
+             * separators.
+             */
+            chaz_MakeFile_write_object_rules(binary->sources, cflags, out);
+        }
+        else {
+            /* Write a pattern rule for each directory. */
+            chaz_MakeFile_write_pattern_rules(binary->dirs, cflags, out);
+            /* Write a rule for each object added with add_src_file. */
+            chaz_MakeFile_write_object_rules(binary->single_sources, cflags,
+                                             out);
+        }
+    }
+}
+
+static void
+chaz_MakeFile_write_object_rules(char **sources, const char *cflags,
+                                 FILE *out) {
+    chaz_CFlags *output_cflags = chaz_CC_new_cflags();
+    const char *output_cflags_string;
+    size_t i;
+
+    chaz_CFlags_set_output_obj(output_cflags, "$@");
+    output_cflags_string = chaz_CFlags_get_string(output_cflags);
+
+    for (i = 0; sources[i]; i++) {
+        const char *source = sources[i];
+        char *obj_path = chaz_MakeBinary_obj_path(source);
+        chaz_MakeRule *rule;
+        char *command;
+
+        if (obj_path == NULL) { continue; }
+
+        rule = S_new_rule(obj_path, source);
+        command = chaz_Util_join(" ", "$(CC) $(CFLAGS)", cflags, source,
+                                 output_cflags_string, NULL);
+        chaz_MakeRule_add_command(rule, command);
+        S_write_rule(rule, out);
+
+        free(command);
+        S_destroy_rule(rule);
+        free(obj_path);
+    }
+
+    chaz_CFlags_destroy(output_cflags);
+}
+
+static void
+chaz_MakeFile_write_pattern_rules(char **dirs, const char *cflags, FILE *out) {
+    const char *obj_ext = chaz_CC_obj_ext();
+    const char *dir_sep = chaz_OS_dir_sep();
+    chaz_CFlags *output_cflags = chaz_CC_new_cflags();
+    const char *output_cflags_string;
+    char *command;
+    size_t i;
+
+    chaz_CFlags_set_output_obj(output_cflags, "$@");
+    output_cflags_string = chaz_CFlags_get_string(output_cflags);
+    command  = chaz_Util_join(" ", "$(CC) $(CFLAGS)", cflags, "$<",
+                              output_cflags_string, NULL);
+
+    for (i = 0; dirs[i]; i++) {
+        const char *dir = dirs[i];
+        char *target = chaz_Util_join("", dir, dir_sep, "%", obj_ext,
+                                      NULL);
+        char *prereq = chaz_Util_join("", dir, dir_sep, "%.c", NULL);
+        chaz_MakeRule *rule = S_new_rule(target, prereq);
+
+        chaz_MakeRule_add_command(rule, command);
+        S_write_rule(rule, out);
+
+        S_destroy_rule(rule);
+        free(prereq);
+        free(target);
+    }
+
+    free(command);
+    chaz_CFlags_destroy(output_cflags);
+}
+
 void
 chaz_MakeVar_append(chaz_MakeVar *var, const char *element) {
     char *value;
@@ -791,6 +995,170 @@ chaz_MakeRule_add_make_command(chaz_MakeRule *rule, const 
char *dir,
     }
 }
 
+static void
+chaz_MakeBinary_destroy(chaz_MakeBinary *self) {
+    size_t i;
+
+    free(self->target_dir);
+    free(self->basename);
+    free(self->version);
+    free(self->major_version);
+    free(self->dollar_var);
+    S_destroy_rule(self->rule);
+
+    for (i = 0; i < self->num_sources; i++) {
+        free(self->sources[i]);
+    }
+    free(self->sources);
+    for (i = 0; i < self->num_single_sources; i++) {
+        free(self->single_sources[i]);
+    }
+    free(self->single_sources);
+    for (i = 0; i < self->num_dirs; i++) {
+        free(self->dirs[i]);
+    }
+    free(self->dirs);
+
+    chaz_CFlags_destroy(self->compile_flags);
+    chaz_CFlags_destroy(self->link_flags);
+
+    free(self);
+}
+
+void
+chaz_MakeBinary_add_src_file(chaz_MakeBinary *self, const char *dir,
+                             const char *filename) {
+    size_t num_sources = self->num_single_sources;
+    size_t alloc_size  = (num_sources + 2) * sizeof(char*);
+    char **sources = (char**)realloc(self->single_sources, alloc_size);
+    char *path;
+
+    if (dir == NULL || strcmp(dir, ".") == 0) {
+        path = chaz_Util_strdup(filename);
+    }
+    else {
+        const char *dir_sep = chaz_OS_dir_sep();
+        path = chaz_Util_join(dir_sep, dir, filename, NULL);
+    }
+
+    /* Add to single_sources. */
+    sources[num_sources]     = path;
+    sources[num_sources+1]   = NULL;
+    self->single_sources     = sources;
+    self->num_single_sources = num_sources + 1;
+
+    chaz_MakeBinary_do_add_src_file(self, path);
+}
+
+void
+chaz_MakeBinary_add_src_dir(chaz_MakeBinary *self, const char *path) {
+    size_t num_dirs = self->num_dirs;
+    char **dirs = (char**)realloc(self->dirs, (num_dirs + 2) * sizeof(char*));
+
+    dirs[num_dirs]   = chaz_Util_strdup(path);
+    dirs[num_dirs+1] = NULL;
+    self->dirs     = dirs;
+    self->num_dirs = num_dirs + 1;
+
+    chaz_Make_list_files(path, "c", chaz_MakeBinary_list_files_callback,
+                         self);
+}
+
+static void
+chaz_MakeBinary_list_files_callback(const char *dir, char *file,
+                                    void *context) {
+    const char *dir_sep = chaz_OS_dir_sep();
+    char *path = chaz_Util_join(dir_sep, dir, file, NULL);
+
+    chaz_MakeBinary_do_add_src_file((chaz_MakeBinary*)context, path);
+    free(path);
+}
+
+static void
+chaz_MakeBinary_do_add_src_file(chaz_MakeBinary *self, const char *path) {
+    size_t num_sources = self->num_sources;
+    size_t alloc_size  = (num_sources + 2) * sizeof(char*);
+    char **sources = (char**)realloc(self->sources, alloc_size);
+    char *obj_path;
+
+    sources[num_sources]   = chaz_Util_strdup(path);
+    sources[num_sources+1] = NULL;
+    self->sources     = sources;
+    self->num_sources = num_sources + 1;
+
+    obj_path = chaz_MakeBinary_obj_path(path);
+    if (obj_path == NULL) {
+        chaz_Util_warn("Invalid source filename: %s", path);
+    }
+    else {
+        chaz_MakeVar_append(self->obj_var, obj_path);
+        free(obj_path);
+    }
+}
+
+static char*
+chaz_MakeBinary_obj_path(const char *src_path) {
+    const char *dir_sep = chaz_OS_dir_sep();
+    const char *obj_ext = chaz_CC_obj_ext();
+    size_t obj_ext_len = strlen(obj_ext);
+    size_t i = strlen(src_path);
+    char *retval;
+
+    while (i > 0) {
+        i -= 1;
+        if (src_path[i] == dir_sep[0]) { return NULL; }
+        if (src_path[i] == '.')        { break; }
+    }
+
+    if (src_path[i] != '.') { return NULL; }
+
+    retval = (char*)malloc(i + obj_ext_len + 1);
+    memcpy(retval, src_path, i);
+    memcpy(retval + i, obj_ext, obj_ext_len + 1);
+
+    return retval;
+}
+
+void
+chaz_MakeBinary_add_prereq(chaz_MakeBinary *self, const char *prereq) {
+    chaz_MakeRule_add_prereq(self->rule, prereq);
+}
+
+char*
+chaz_MakeBinary_obj_string(chaz_MakeBinary *self) {
+    char *retval = chaz_Util_strdup("");
+    size_t i;
+
+    for (i = 0; i < self->num_sources; i++) {
+        const char *sep = retval[0] == '\0' ? "" : " ";
+        char *obj_path = chaz_MakeBinary_obj_path(self->sources[i]);
+        char *tmp;
+
+        if (obj_path == NULL) { continue; }
+
+        tmp = chaz_Util_join("", retval, sep, obj_path, NULL);
+        free(retval);
+        retval = tmp;
+    }
+
+    return retval;
+}
+
+const char*
+chaz_MakeBinary_get_target(chaz_MakeBinary *self) {
+    return self->rule->targets;
+}
+
+chaz_CFlags*
+chaz_MakeBinary_get_compile_flags(chaz_MakeBinary *self) {
+    return self->compile_flags;
+}
+
+chaz_CFlags*
+chaz_MakeBinary_get_link_flags(chaz_MakeBinary *self) {
+    return self->link_flags;
+}
+
 void
 chaz_Make_list_files(const char *dir, const char *ext,
                      chaz_Make_list_files_callback_t callback, void *context) {

http://git-wip-us.apache.org/repos/asf/lucy-charmonizer/blob/1ce65627/src/Charmonizer/Core/Make.h
----------------------------------------------------------------------
diff --git a/src/Charmonizer/Core/Make.h b/src/Charmonizer/Core/Make.h
index 25e99ea..f2ab064 100644
--- a/src/Charmonizer/Core/Make.h
+++ b/src/Charmonizer/Core/Make.h
@@ -25,11 +25,11 @@ extern "C" {
 #endif
 
 #include "Charmonizer/Core/CFlags.h"
-#include "Charmonizer/Core/Library.h"
 
 typedef struct chaz_MakeFile chaz_MakeFile;
 typedef struct chaz_MakeVar chaz_MakeVar;
 typedef struct chaz_MakeRule chaz_MakeRule;
+typedef struct chaz_MakeBinary chaz_MakeBinary;
 
 typedef void (*chaz_Make_list_files_callback_t)(const char *dir, char *file,
                                                 void *context);
@@ -117,59 +117,44 @@ chaz_MakeFile_clean_rule(chaz_MakeFile *makefile);
 chaz_MakeRule*
 chaz_MakeFile_distclean_rule(chaz_MakeFile *makefile);
 
-/** Add a rule to link an executable. The executable will also be added to the
- * list of files to clean.
+/** Add an executable. Returns a chaz_MakeBinary object.
  *
- * @param makefile The makefile.
- * @param exe The name of the executable.
- * @param sources The list of source files.
- * @param link_flags Additional link flags.
+ * @param dir The target directory or NULL for the current directory.
+ * @param basename The name of the executable without extension.
  */
-chaz_MakeRule*
-chaz_MakeFile_add_exe(chaz_MakeFile *makefile, const char *exe,
-                      const char *sources, chaz_CFlags *link_flags);
+chaz_MakeBinary*
+chaz_MakeFile_add_exe(chaz_MakeFile *self, const char *dir,
+                      const char *basename);
 
-/** Add a rule to compile and link an executable. The executable will also be
- * added to the list of files to clean.
+/** Add a shared library. The library will be built in the current directory.
+ * Returns a chaz_MakeBinary object.
  *
- * @param makefile The makefile.
- * @param exe The name of the executable.
- * @param sources The list of source files.
- * @param cflags Additional compiler flags.
+ * @param dir The target directory or NULL for the current directory.
+ * @param basename The name of the library without prefix and extension.
+ * @param version The version of the library.
+ * @param major_version The major version of the library.
  */
-chaz_MakeRule*
-chaz_MakeFile_add_compiled_exe(chaz_MakeFile *makefile, const char *exe,
-                               const char *sources, chaz_CFlags *cflags);
+chaz_MakeBinary*
+chaz_MakeFile_add_shared_lib(chaz_MakeFile *self, const char *dir,
+                             const char *basename, const char *version,
+                             const char *major_version);
 
-/** Add a rule to link a shared library. The shared library will also be added
- * to the list of files to clean.
+/** Add a static library. The library will be built in the current directory.
+ * Returns a chaz_MakeBinary object.
  *
- * @param makefile The makefile.
- * @param lib The shared library.
- * @param sources The list of source files.
- * @param link_flags Additional link flags.
+ * @param dir The target directory or NULL for the current directory.
+ * @param basename The name of the library without prefix and extension.
  */
-chaz_MakeRule*
-chaz_MakeFile_add_shared_lib(chaz_MakeFile *makefile, chaz_Lib *lib,
-                             const char *sources, chaz_CFlags *link_flags);
-
-/** Add a rule to create a static library. The static library will also be 
added
- * to the list of files to clean.
- *
- * @param makefile The makefile.
- * @param lib The static library.
- * @param objects The list of object files to be archived.
- */
-chaz_MakeRule*
-chaz_MakeFile_add_static_lib(chaz_MakeFile *makefile, chaz_Lib *lib,
-                             const char *objects);
+chaz_MakeBinary*
+chaz_MakeFile_add_static_lib(chaz_MakeFile *self, const char *dir,
+                             const char *basename);
 
 /** Add a rule to build the lemon parser generator.
  *
  * @param makefile The makefile.
  * @param dir The lemon directory.
  */
-chaz_MakeRule*
+chaz_MakeBinary*
 chaz_MakeFile_add_lemon_exe(chaz_MakeFile *makefile, const char *dir);
 
 /** Add a rule for a lemon grammar.
@@ -181,16 +166,6 @@ chaz_MakeRule*
 chaz_MakeFile_add_lemon_grammar(chaz_MakeFile *makefile,
                                 const char *base_name);
 
-/** Override compiler flags for a single object file.
- *
- * @param makefile The makefile.
- * @param obj The object file.
- * @param cflags Compiler flags.
- */
-chaz_MakeRule*
-chaz_MakeFile_override_cflags(chaz_MakeFile *makefile, const char *obj,
-                              chaz_CFlags *cflags);
-
 /** Write the makefile to a file named 'Makefile' in the current directory.
  *
  * @param makefile The makefile.
@@ -267,6 +242,49 @@ void
 chaz_MakeRule_add_make_command(chaz_MakeRule *rule, const char *dir,
                                const char *target);
 
+/** Add a source file for the binary.
+ *
+ * @param dir The source directory or NULL for the current directory.
+ * @param filename The filename.
+ */
+void
+chaz_MakeBinary_add_src_file(chaz_MakeBinary *self, const char *dir,
+                             const char *filename);
+
+/** Add all .c files in a directory as sources for the binary.
+ *
+ * @param path The path to the directory.
+ */
+void
+chaz_MakeBinary_add_src_dir(chaz_MakeBinary *self, const char *path);
+
+/** Add a prerequisite to the make rule of the binary.
+ *
+ * @param prereq The prerequisite.
+ */
+void
+chaz_MakeBinary_add_prereq(chaz_MakeBinary *self, const char *prereq);
+
+/** Return a list of all objects separated by space.
+ */
+char*
+chaz_MakeBinary_obj_string(chaz_MakeBinary *self);
+
+/** Accessor for target.
+ */
+const char*
+chaz_MakeBinary_get_target(chaz_MakeBinary *self);
+
+/** Accessor for compile flags.
+ */
+chaz_CFlags*
+chaz_MakeBinary_get_compile_flags(chaz_MakeBinary *self);
+
+/** Accessor for link flags.
+ */
+chaz_CFlags*
+chaz_MakeBinary_get_link_flags(chaz_MakeBinary *self);
+
 #ifdef __cplusplus
 }
 #endif

http://git-wip-us.apache.org/repos/asf/lucy-charmonizer/blob/1ce65627/src/Charmonizer/Probe/Floats.c
----------------------------------------------------------------------
diff --git a/src/Charmonizer/Probe/Floats.c b/src/Charmonizer/Probe/Floats.c
index 609bee8..e2f8d41 100644
--- a/src/Charmonizer/Probe/Floats.c
+++ b/src/Charmonizer/Probe/Floats.c
@@ -90,7 +90,7 @@ chaz_Floats_math_library(void) {
         return NULL;
     }
 
-    chaz_CFlags_add_external_library(temp_cflags, "m");
+    chaz_CFlags_add_external_lib(temp_cflags, "m");
     output = chaz_CC_capture_output(sqrt_code, &output_len);
     chaz_CFlags_clear(temp_cflags);
 

Reply via email to