]> git.tdb.fi Git - builder.git/commitdiff
Build and install import libraries on windows
authorMikko Rasa <tdb@tdb.fi>
Fri, 7 Sep 2012 18:37:19 +0000 (21:37 +0300)
committerMikko Rasa <tdb@tdb.fi>
Fri, 7 Sep 2012 18:37:19 +0000 (21:37 +0300)
source/builder.cpp
source/exportdefinitions.cpp [new file with mode: 0644]
source/exportdefinitions.h [new file with mode: 0644]
source/gnulinker.cpp
source/importlibrary.cpp
source/importlibrary.h
source/mingwdlltool.cpp [new file with mode: 0644]
source/mingwdlltool.h [new file with mode: 0644]
source/sharedlibrary.cpp
source/sharedlibrary.h

index 3344429c433728f01a54ca6c2ea3ae98e166426f..6794842c50d2c872e8ac36e560d2d2dc58fd624c 100644 (file)
@@ -21,6 +21,7 @@
 #include "gnucxxcompiler.h"
 #include "gnulinker.h"
 #include "installedfile.h"
+#include "mingwdlltool.h"
 #include "package.h"
 #include "pkgconfiggenerator.h"
 #include "sharedlibrary.h"
@@ -203,6 +204,8 @@ Builder::Builder(int argc, char **argv):
        toolchain.add_tool(new Copy(*this));
        toolchain.add_tool(new Tar(*this));
        toolchain.add_tool(new PkgConfigGenerator(*this));
+       if(current_arch->get_system()=="windows")
+               toolchain.add_tool(new MingwDllTool(*this, *current_arch));
 }
 
 Builder::~Builder()
diff --git a/source/exportdefinitions.cpp b/source/exportdefinitions.cpp
new file mode 100644 (file)
index 0000000..cc50e16
--- /dev/null
@@ -0,0 +1,17 @@
+#include "component.h"
+#include "exportdefinitions.h"
+#include "sourcepackage.h"
+
+using namespace Msp;
+
+ExportDefinitions::ExportDefinitions(Builder &b, const Component &c, SharedLibrary &l):
+       FileTarget(b, c.get_package(), generate_target_path(c)),
+       lib(l)
+{
+       component = &c;
+}
+
+FS::Path ExportDefinitions::generate_target_path(const Component &comp)
+{
+       return comp.get_package().get_temp_dir()/comp.get_name()/(comp.get_name()+".def");
+}
diff --git a/source/exportdefinitions.h b/source/exportdefinitions.h
new file mode 100644 (file)
index 0000000..73d6f0f
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef EXPORTDEFINITIONS_H_
+#define EXPORTDEFINITIONS_H_
+
+#include "filetarget.h"
+
+class SharedLibrary;
+
+/**
+An export definition file for a shared library.  Only used on Windows.
+*/
+class ExportDefinitions: public FileTarget
+{
+private:
+       SharedLibrary &lib;
+
+public:
+       ExportDefinitions(Builder &, const Component &, SharedLibrary &);
+private:
+       static Msp::FS::Path generate_target_path(const Component &);
+
+public:
+       virtual const char *get_type() const { return "ExportDefinitions"; }
+
+       SharedLibrary &get_library() const { return lib; }
+};
+
+#endif
index ce51c44ae503cefb58fdefc6d026b9f7071f46ed..114bf09c84404910f480a904aa952761366eb2fa 100644 (file)
@@ -7,6 +7,7 @@
 #include "builder.h"
 #include "component.h"
 #include "executable.h"
+#include "exportdefinitions.h"
 #include "externaltask.h"
 #include "gnucompiler.h"
 #include "gnulinker.h"
@@ -69,7 +70,18 @@ Target *GnuLinker::create_target(const list<Target *> &sources, const string &ar
        const Component &comp = *objs.front()->get_component();
        Binary *bin = 0;
        if(arg=="shared")
-               bin = new SharedLibrary(builder, comp, objs);
+       {
+               SharedLibrary *shlib = new SharedLibrary(builder, comp, objs);
+               if(architecture->get_system()=="windows")
+               {
+                       ExportDefinitions *exp = new ExportDefinitions(builder, comp, *shlib);
+                       shlib->add_side_effect(*exp);
+                       const Tool &dlltool = builder.get_toolchain().get_tool("DLL");
+                       ImportLibrary *imp = dynamic_cast<ImportLibrary *>(dlltool.create_target(*exp));
+                       shlib->set_import_library(imp);
+               }
+               bin = shlib;
+       }
        else
                bin = new Executable(builder, comp, objs);
        bin->set_tool(*linker);
@@ -82,8 +94,13 @@ Target *GnuLinker::create_install(Target &target) const
        {
                const Tool &copy = builder.get_toolchain().get_tool("CP");
                InstalledFile *inst_tgt = dynamic_cast<InstalledFile *>(copy.create_target(target));
-               const Pattern &pattern = architecture->get_shared_library_patterns().front();
-               inst_tgt->set_symlink(pattern.apply(shlib->get_libname()));
+               if(architecture->get_system()=="windows")
+                       builder.add_installed_target(*shlib->get_import_library());
+               else
+               {
+                       const Pattern &pattern = architecture->get_shared_library_patterns().front();
+                       inst_tgt->set_symlink(pattern.apply(shlib->get_libname()));
+               }
                return inst_tgt;
        }
        else
@@ -151,11 +168,19 @@ Task *GnuLinker::Linker::run(const Target &target) const
 
        const Component &comp = *bin.get_component();
 
+       FS::Path work_dir = comp.get_package().get_source_directory();
+
        if(const SharedLibrary *shlib = dynamic_cast<const SharedLibrary *>(&bin))
        {
                argv.push_back("-shared");
                argv.push_back("-fPIC");
-               if(!shlib->get_soname().empty())
+               const Target::Dependencies &side_eff = target.get_side_effects();
+               for(Target::Dependencies::const_iterator i=side_eff.begin(); i!=side_eff.end(); ++i)
+               {
+                       if(ExportDefinitions *exp = dynamic_cast<ExportDefinitions *>(*i))
+                               argv.push_back("-Wl,--output-def,"+relative(exp->get_path(), work_dir).str());
+               }
+               if(architecture->get_system()!="windows" && !shlib->get_soname().empty())
                        argv.push_back("-Wl,-soname,"+shlib->get_soname());
        }
 
@@ -171,8 +196,6 @@ Task *GnuLinker::Linker::run(const Target &target) const
        if(architecture->get_bits()!=native_arch.get_bits())
                argv.push_back(format("-m%d", architecture->get_bits()));
 
-       FS::Path work_dir = comp.get_package().get_source_directory();
-
        argv.push_back("-o");
        argv.push_back(relative(bin.get_path(), work_dir).str());
 
@@ -194,7 +217,11 @@ Task *GnuLinker::Linker::run(const Target &target) const
                }
                else if(ImportLibrary *imp = dynamic_cast<ImportLibrary *>(tgt))
                {
-                       argv.push_back(imp->get_path().str());
+                       shlib = imp->get_shared_library();
+                       if(shlib)
+                               argv.push_back("-l"+shlib->get_libname());
+                       else
+                               argv.push_back(imp->get_path().str());
                        static_link_ok = false;
                }
        }
index 60e5511b96ff08ebb4be74aa0fa5e39182f2eddd..9ac441f419ea6d683eb86c07890f622232711084 100644 (file)
@@ -1,8 +1,27 @@
 #include <msp/strings/format.h>
+#include "component.h"
+#include "exportdefinitions.h"
 #include "importlibrary.h"
+#include "sourcepackage.h"
 
+using namespace std;
 using namespace Msp;
 
 ImportLibrary::ImportLibrary(Builder &b, const FS::Path &p):
-       FileTarget(b, p)
+       FileTarget(b, p),
+       shared_lib(0)
 { }
+
+ImportLibrary::ImportLibrary(Builder &b, const Component &c, ExportDefinitions &exp):
+       FileTarget(b, c.get_package(), c.get_package().get_out_dir()/format("lib%s.dll.a", c.get_name())),
+       shared_lib(&exp.get_library())
+{
+       component = &c;
+       add_dependency(exp);
+
+       install_location = "lib";
+
+       const string &version = component->get_package().get_interface_version();
+       if(!version.empty())
+               install_filename = format("lib%s-%s.dll.a", c.get_name(), version);
+}
index 86d26f45d201981f52f82f2c4d22bb245fefa71f..99db24d26fac2a0a1134f94d6cc37f0a598fed95 100644 (file)
@@ -3,16 +3,25 @@
 
 #include "filetarget.h"
 
+class ExportDefinitions;
+class SharedLibrary;
+
 /**
 A special case of static library which pulls in a shared library.  Used on
 platforms with no true dynamic linking support.
 */
 class ImportLibrary: public FileTarget
 {
+private:
+       SharedLibrary *shared_lib;
+
 public:
        ImportLibrary(Builder &, const Msp::FS::Path &);
+       ImportLibrary(Builder &, const Component &, ExportDefinitions &);
 
        virtual const char *get_type() const { return "ImportLibrary"; }
+
+       SharedLibrary *get_shared_library() const { return shared_lib; }
 };
 
 #endif
diff --git a/source/mingwdlltool.cpp b/source/mingwdlltool.cpp
new file mode 100644 (file)
index 0000000..582963e
--- /dev/null
@@ -0,0 +1,84 @@
+#include <cstdlib>
+#include <msp/fs/utils.h>
+#include <msp/strings/format.h>
+#include "architecture.h"
+#include "builder.h"
+#include "component.h"
+#include "exportdefinitions.h"
+#include "externaltask.h"
+#include "importlibrary.h"
+#include "installedfile.h"
+#include "mingwdlltool.h"
+#include "sharedlibrary.h"
+#include "sourcepackage.h"
+
+using namespace std;
+using namespace Msp;
+
+MingwDllTool::MingwDllTool(Builder &b, const Architecture &a):
+       Tool(b, a, "DLL")
+{
+       string command = "dlltool";
+       if(architecture->is_cross())
+               command = format("%s-%s", architecture->get_cross_prefix(), command);
+       executable = builder.get_vfs().find_binary(command);
+}
+
+Target *MingwDllTool::create_target(const list<Target *> &sources, const string &) const
+{
+       if(sources.size()!=1)
+               throw invalid_argument("MingwDllTool::create_target");
+       ExportDefinitions &def = dynamic_cast<ExportDefinitions &>(*sources.front());
+       ImportLibrary *imp = new ImportLibrary(builder, *def.get_component(), def);
+       imp->set_tool(*this);
+       return imp;
+}
+
+Target *MingwDllTool::create_install(Target &target) const
+{
+       if(ImportLibrary *imp = dynamic_cast<ImportLibrary *>(&target))
+       {
+               const Tool &copy = builder.get_toolchain().get_tool("CP");
+               InstalledFile *inst_tgt = dynamic_cast<InstalledFile *>(copy.create_target(target));
+               string link_name = format("lib%s.dll.a", imp->get_shared_library()->get_libname());
+               inst_tgt->set_symlink(link_name);
+               return inst_tgt;
+       }
+       else
+               return 0;
+}
+
+Task *MingwDllTool::run(const Target &target) const
+{
+       const ImportLibrary &imp = dynamic_cast<const ImportLibrary &>(target);
+       const ExportDefinitions &exp = dynamic_cast<const ExportDefinitions &>(*imp.get_dependencies().front());
+       const SharedLibrary &shlib = exp.get_library();
+
+       vector<string> argv;
+       argv.push_back(executable->get_path().str());
+
+       /* dlltool is stupid and puts temporary files in the working directory by
+       default */
+       argv.push_back("--temp-prefix");
+       char random[8];
+       for(unsigned i=0; i<8; ++i)
+               random[i] = 'a'+(rand()%26);
+       argv.push_back(string("/tmp/")+string(random, 8));
+
+       const Component &comp = *imp.get_component();
+       FS::Path work_dir = comp.get_package().get_source_directory();
+
+       argv.push_back("-d");
+       argv.push_back(relative(exp.get_path(), work_dir).str());
+
+       argv.push_back("-D");
+       if(shlib.get_install_filename().empty())
+               argv.push_back(FS::basename(shlib.get_path()));
+       else
+               argv.push_back(shlib.get_install_filename());
+
+       argv.push_back("-l");
+       argv.push_back(relative(imp.get_path(), work_dir).str());
+
+       return new ExternalTask(argv, work_dir);
+}
diff --git a/source/mingwdlltool.h b/source/mingwdlltool.h
new file mode 100644 (file)
index 0000000..25a1e10
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef DLLTOOL_H_
+#define DLLTOOL_H_
+
+#include "tool.h"
+
+class MingwDllTool: public Tool
+{
+public:
+       MingwDllTool(Builder &, const Architecture &);
+
+       virtual Target *create_target(const std::list<Target *> &, const std::string &) const;
+       virtual Target *create_install(Target &) const;
+
+       virtual Task *run(const Target &) const;
+};
+
+#endif
index 56f9b32d3e09d5056717faf93d663b57d80648ec..06a99442b2fb47377044546d1646d7d599da5dcb 100644 (file)
@@ -9,7 +9,8 @@ using namespace std;
 using namespace Msp;
 
 SharedLibrary::SharedLibrary(Builder &b, const Msp::FS::Path &p):
-       Binary(b, p)
+       Binary(b, p),
+       import_lib(0)
 {
        libname = FS::basepart(FS::basename(path));
        if(!libname.compare(0, 3, "lib"))
@@ -18,7 +19,8 @@ SharedLibrary::SharedLibrary(Builder &b, const Msp::FS::Path &p):
 
 SharedLibrary::SharedLibrary(Builder &b, const Component &c, const list<ObjectFile *> &objs):
        Binary(b, c, generate_filename(c), objs),
-       libname(c.get_name())
+       libname(c.get_name()),
+       import_lib(0)
 {
        install_location = "lib";
        if(component->get_type()==Component::MODULE)
@@ -48,3 +50,8 @@ string SharedLibrary::generate_filename(const Component &comp)
                return arch.get_shared_library_patterns().front().apply(comp.get_name());
        }
 }
+
+void SharedLibrary::set_import_library(ImportLibrary *imp)
+{
+       import_lib = imp;
+}
index 5331ef58290d8995b7cabdc5b5fadd0849cc7e9e..c40bccd3bfde548e21efdf2d7b132c93e1eb835b 100644 (file)
@@ -3,17 +3,23 @@
 
 #include "binary.h"
 
+class ImportLibrary;
+
 /**
 Represents a shared library.  It has two special properties: libname and
 soname.  Libname is the name used by the linker.  Soname is the canonical
 filename of the library, including version number.  If the owning package has
 no version, soname will be empty.
+
+A SharedLibrary can also store a pointer to the associated ImportLibrary, for
+platforms that need one.
 */
 class SharedLibrary: public Binary
 {
 private:
        std::string libname;
        std::string soname;
+       ImportLibrary *import_lib;
 
 public:
        SharedLibrary(Builder &, const Msp::FS::Path &);
@@ -25,6 +31,9 @@ public:
        virtual const char *get_type() const { return "SharedLibrary"; }
        const std::string &get_libname() const { return libname; }
        const std::string &get_soname() const { return soname; }
+
+       void set_import_library(ImportLibrary *);
+       ImportLibrary *get_import_library() const { return import_lib; }
 };
 
 #endif