From: Mikko Rasa Date: Sun, 27 Aug 2006 12:45:01 +0000 (+0000) Subject: Add files. X-Git-Tag: 0.9~71 X-Git-Url: http://git.tdb.fi/?a=commitdiff_plain;h=4dc31cca056ea293d320928f61fef0558089d32d;p=builder.git Add files. Doesn't build anything yet. --- diff --git a/Build b/Build new file mode 100644 index 0000000..4db65e6 --- /dev/null +++ b/Build @@ -0,0 +1,16 @@ +package "builder" +{ + version "0.1"; + description "Mikkosoft Productions software builder"; + + require "mspframework"; + require "mspparser"; + require "msppath"; + require "mspregex++"; + + program "builder" + { + source "source"; + install true; + }; +}; diff --git a/source/builder.cpp b/source/builder.cpp new file mode 100644 index 0000000..3f93a67 --- /dev/null +++ b/source/builder.cpp @@ -0,0 +1,222 @@ +#include +#include +#include +#include +#include "builder.h" +#include "executable.h" +#include "header.h" +#include "misc.h" +#include "objectfile.h" +#include "package.h" +#include "virtualtarget.h" + +using namespace std; +using namespace Msp; + +Builder::Builder(int argc, char **argv): + verbose(1), + cwd(Path::getcwd()) +{ + for(int i=1; isecond; + + list argv; + argv.push_back("pkg-config"); + argv.push_back("--variable=source"); + argv.push_back(n); + Path::Path srcdir=run_command(argv); + if(srcdir.empty()) + { + string dirname=n; + if(dirname.compare(0, 3, "msp")) + dirname.erase(0, 3); + if(Path::exists(cwd/dirname)) + srcdir=cwd/dirname; + else if(Path::exists(cwd/".."/dirname)) + srcdir=cwd/".."/dirname; + } + else + srcdir=strip(srcdir.str()); + + if(!srcdir.empty()) + load_build_file(srcdir/"Build"); + + return 0; +} + +Target *Builder::get_target(const string &n) +{ + TargetMap::iterator i=targets.find(n); + if(i!=targets.end()) + return i->second; + return 0; +} + +Target *Builder::get_header(const string &include, const string &from, const list &path) +{ + string id=from+":"+include; + TargetMap::iterator i=includes.find(id); + if(i!=includes.end()) + return i->second; + + string fn=include.substr(1); + Target *tgt; + if(include[0]=='"' && (tgt=check_header(Path::Path(from)/fn))) + return tgt; + if((tgt=check_header(Path::Path("/usr/include")/fn))) + return tgt; + if((tgt=check_header(Path::Path("/usr/include/c++/4.1.2")/fn))) + return tgt; + for(list::const_iterator j=path.begin(); j!=path.end(); ++j) + if((tgt=check_header(Path::Path(*j)/fn))) + return tgt; + + return 0; +} + +int Builder::main() +{ + if(load_build_file("Build")) + { + cerr<<"No build info here.\n"; + return 1; + } + + default_pkg=packages.begin()->second; + + while(!new_pkgs.empty()) + { + Package *pkg=new_pkgs.front(); + new_pkgs.erase(new_pkgs.begin()); + pkg->resolve_refs(); + } + + cout<<"Active packages:"; + for(PackageMap::iterator i=packages.begin(); i!=packages.end(); ++i) + { + cout<<' '<second->get_name(); + if(i->second->get_buildable()) + cout<<'*'; + } + cout<<'\n'; + + create_targets(); + + for(TargetMap::iterator i=targets.begin(); i!=targets.end(); ++i) + cout<second->get_name()<<' '<second->get_type()<<'\n'; + + cout<<"Active targets: "<second->get_source()<<'\n'; + const ComponentList &components=i->second->get_components(); + for(ComponentList::const_iterator j=components.begin(); j!=components.end(); ++j) + { + Path::Path base=i->second->get_source()/j->get_source(); + cout< files=list_files(base); + + list objs; + for(list::iterator k=files.begin(); k!=files.end(); ++k) + { + Path::Path fn=base/ *k; + //cout<<*k<<'\n'; + string ext=Path::splitext(*k).ext; + if(ext==".cpp" || ext==".c") + { + SourceFile *src=new SourceFile(*this, &*j, fn.str()); + add_target(src); + + ObjectFile *obj=new ObjectFile(*this, *j, *src); + add_target(obj); + objs.push_back(obj); + } + else if(ext==".h") + add_target(new Header(*this, &*j, fn.str())); + } + + Executable *exe=new Executable(*this, *j, objs); + add_target(exe); + if(i->second==default_pkg) + def_tgt->add_depend(exe); + } + } + + while(!new_tgts.empty()) + { + Target *tgt=new_tgts.front(); + new_tgts.erase(new_tgts.begin()); + tgt->find_depends(); + } +} + +Target *Builder::check_header(const Msp::Path::Path &fn) +{ + Target *tgt=get_target(fn.str()); + if(tgt) return tgt; + + if(Path::exists(fn)) + { + add_target(tgt=new SystemHeader(*this, fn.str())); + return tgt; + } + return 0; +} + +void Builder::add_target(Target *t) +{ + targets.insert(TargetMap::value_type(t->get_name(), t)); + new_tgts.push_back(t); +} + +Application::RegApp Builder::reg; + +Builder::Loader::Loader(Builder &b, const Path::Path &s): + bld(b), + src(s) +{ + add("package", &Loader::package); +} + +void Builder::Loader::package(const string &n) +{ + Package *pkg=new Package(bld, n, src); + load_sub(*pkg); + bld.packages.insert(PackageMap::value_type(n, pkg)); + bld.new_pkgs.push_back(pkg); + //cout<<"loaded "<get_name()<<'\n'; +} + diff --git a/source/builder.h b/source/builder.h new file mode 100644 index 0000000..f66b310 --- /dev/null +++ b/source/builder.h @@ -0,0 +1,56 @@ +#ifndef BUILDER_H_ +#define BUILDER_H_ + +#include +#include +#include +#include +#include +#include + +class Package; +class Target; + +class Builder: public Msp::Application +{ +public: + Builder(int, char **); + unsigned get_verbose() const { return verbose; } + Package *get_package(const std::string &); + Target *get_target(const std::string &); + Target *get_header(const std::string &, const std::string &, const std::list &); + int main(); +private: + class Loader: public Msp::Parser::Loader + { + public: + Loader(Builder &, const Msp::Path::Path &); + private: + Builder &bld; + Msp::Path::Path src; + + void package(const std::string &); + }; + + typedef std::map PackageMap; + typedef std::map TargetMap; + + std::list cmdline_targets; + TargetMap targets; + PackageMap packages; + unsigned verbose; + Package *default_pkg; + Msp::Path::Path cwd; + std::list new_pkgs; + TargetMap includes; + std::list new_tgts; + + int load_build_file(const Msp::Path::Path &); + void create_targets(); + Target *check_header(const Msp::Path::Path &); + void add_target(Target *); + + static Msp::Application::RegApp reg; +}; + +#endif diff --git a/source/buildinfo.h b/source/buildinfo.h new file mode 100644 index 0000000..02549ea --- /dev/null +++ b/source/buildinfo.h @@ -0,0 +1,23 @@ +#ifndef BUILDINFO_H_ +#define BUILDINFO_H_ + +#include +#include + +class BuildInfo +{ +public: + typedef std::list InfoList; + + InfoList cflags; + InfoList defines; + InfoList incpath; + InfoList ldflags; + InfoList libpath; + InfoList libs; + + void add(const BuildInfo &); + void unique(); +}; + +#endif diff --git a/source/component.cpp b/source/component.cpp new file mode 100644 index 0000000..bab7ba1 --- /dev/null +++ b/source/component.cpp @@ -0,0 +1,23 @@ +#include "component.h" +#include "package.h" + +using namespace std; + +Component::Component(Package &p, Type t, const string &n): + pkg(p), + type(t), + name(n) +{ } + +Component::Loader::Loader(Component &c): + comp(c) +{ + add("source", &Loader::source); + add("install", &Component::install); + add("install_headers", &Component::install_headers); +} + +void Component::Loader::source(const string &s) +{ + comp.source=comp.pkg.get_source()/s; +} diff --git a/source/component.h b/source/component.h new file mode 100644 index 0000000..c5e1d0c --- /dev/null +++ b/source/component.h @@ -0,0 +1,49 @@ +#ifndef COMPONENT_H_ +#define COMPONENT_H_ + +#include +#include +#include +#include "buildinfo.h" + +class Package; + +class Component +{ +public: + class Loader: public Msp::Parser::Loader + { + public: + Loader(Component &); + Component &get_object() { return comp; } + private: + Component ∁ + + void source(const std::string &); + }; + + enum Type + { + PROGRAM, + LIBRARY, + MODULE + }; + + Component(Package &, Type, const std::string &); + const Package &get_package() const { return pkg; } + Type get_type() const { return type; } + const std::string &get_name() const { return name; } + const Msp::Path::Path &get_source() const { return source; } + const BuildInfo &get_build_info() const { return build_info; } +protected: + Package &pkg; + Type type; + std::string name; + Msp::Path::Path source; + bool install; + std::string install_headers; + BuildInfo build_info; +}; +typedef std::list ComponentList; + +#endif diff --git a/source/executable.cpp b/source/executable.cpp new file mode 100644 index 0000000..2dfeee8 --- /dev/null +++ b/source/executable.cpp @@ -0,0 +1,28 @@ +#include "component.h" +#include "executable.h" +#include "objectfile.h" +#include "package.h" + +using namespace std; + +Executable::Executable(Builder &b, const Component &c, const list &objs): + Target(b, &c.get_package(), generate_target_name(c)), + comp(c) +{ + for(list::const_iterator i=objs.begin(); i!=objs.end(); ++i) + add_depend(*i); +} + +string Executable::generate_target_name(const Component &comp) +{ + string prefix; + string suffix; + + if(comp.get_type()==Component::LIBRARY) + { + prefix="lib"; + suffix=".so"; + } + + return (comp.get_package().get_source()/(prefix+comp.get_name()+suffix)).str(); +} diff --git a/source/executable.h b/source/executable.h new file mode 100644 index 0000000..3e34851 --- /dev/null +++ b/source/executable.h @@ -0,0 +1,21 @@ +#ifndef EXECUTABLE_H_ +#define EXECUTABLE_H_ + +#include "target.h" + +class Component; +class ObjectFile; + +class Executable: public Target +{ +public: + Executable(Builder &, const Component &, const std::list &); + const char *get_type() const { return "Executable"; } + void find_depends() { } +private: + const Component ∁ + + static std::string generate_target_name(const Component &); +}; + +#endif diff --git a/source/header.h b/source/header.h new file mode 100644 index 0000000..6541cd4 --- /dev/null +++ b/source/header.h @@ -0,0 +1,21 @@ +#ifndef HEADER_H_ +#define HEADER_H_ + +#include "sourcefile.h" + +class Header: public SourceFile +{ +public: + Header(Builder &b, const Component *c, const std::string &f): SourceFile(b,c,f) { } + const char *get_type() const { return "Header"; } +}; + +class SystemHeader: public Header +{ +public: + SystemHeader(Builder &b, const std::string &f): Header(b,0,f) { } + const char *get_type() const { return "SystemHeader"; } + void find_depends() { } +}; + +#endif diff --git a/source/misc.cpp b/source/misc.cpp new file mode 100644 index 0000000..37616a9 --- /dev/null +++ b/source/misc.cpp @@ -0,0 +1,51 @@ +#include +#include +#include +#include "misc.h" + +using namespace std; +using namespace Msp; + +string run_command(const list &argv) +{ + int pfd[2]; + pipe(pfd); + + string result; + + pid_t pid=fork(); + if(pid==0) + { + char *argv_[argv.size()+1]; + for(CountingIterator::const_iterator> i=argv.begin(); i!=argv.end(); ++i) + argv_[i.count()]=strdup(i->c_str()); + argv_[argv.size()]=0; + close(pfd[0]); + dup2(pfd[1], 1); + dup2(pfd[1], 2); + execvp(argv_[0], argv_); + ::exit(1); + } + else if(pid==-1) + cerr<<"Failed to execute "< +#include + +std::string run_command(const std::list &); + +#endif diff --git a/source/objectfile.cpp b/source/objectfile.cpp new file mode 100644 index 0000000..b308c2b --- /dev/null +++ b/source/objectfile.cpp @@ -0,0 +1,21 @@ +#include +#include "builder.h" +#include "component.h" +#include "objectfile.h" +#include "package.h" +#include "sourcefile.h" + +using namespace std; +using namespace Msp; + +ObjectFile::ObjectFile(Builder &b, const Component &c, SourceFile &src): + Target(b, &c.get_package(), generate_target_name(c, src.get_name())), + comp(c) +{ + add_depend(&src); +} + +string ObjectFile::generate_target_name(const Component &comp, const string &src) +{ + return (comp.get_package().get_source()/"temp"/comp.get_name()/(Path::splitext(src.substr(src.rfind('/')+1)).base+".o")).str(); +} diff --git a/source/objectfile.h b/source/objectfile.h new file mode 100644 index 0000000..d270529 --- /dev/null +++ b/source/objectfile.h @@ -0,0 +1,21 @@ +#ifndef OBJECTFILE_H_ +#define OBJECTFILE_H_ + +#include "target.h" + +class Component; +class SourceFile; + +class ObjectFile: public Target +{ +public: + ObjectFile(Builder &, const Component &, SourceFile &); + const char *get_type() const { return "ObjectFile"; } + void find_depends() { } +private: + const Component ∁ + + static std::string generate_target_name(const Component &, const std::string &); +}; + +#endif diff --git a/source/package.cpp b/source/package.cpp new file mode 100644 index 0000000..5cf7e07 --- /dev/null +++ b/source/package.cpp @@ -0,0 +1,66 @@ +#include "builder.h" +#include "package.h" + +using namespace std; +using namespace Msp; + +PackageRef::PackageRef(Builder &b, const string &n): + builder(b), + name(n), + package(0) +{ } + +Package *PackageRef::get_package() +{ + if(!package) + package=builder.get_package(name); + return package; +} + +Package::Package(Builder &b, const string &n, const Path::Path &s): + builder(b), + name(n), + source(s), + buildable(false) +{ +} + +void Package::resolve_refs() +{ + for(list::iterator i=requires.begin(); i!=requires.end(); ++i) + i->get_package(); +} + +Package::Loader::Loader(Package &p): + pkg(p) +{ + add("version", &Package::version); + add("description", &Package::description); + add("require", &Loader::require); + add("program", &Loader::program); + add("library", &Loader::library); +} + +Package::Loader::~Loader() +{ + pkg.buildable=true; +} + +void Package::Loader::require(const string &n) +{ + pkg.requires.push_back(PackageRef(pkg.builder, n)); +} + +void Package::Loader::program(const std::string &n) +{ + Component prog(pkg, Component::PROGRAM, n); + load_sub(prog); + pkg.components.push_back(prog); +} + +void Package::Loader::library(const std::string &n) +{ + Component prog(pkg, Component::LIBRARY, n); + load_sub(prog); + pkg.components.push_back(prog); +} diff --git a/source/package.h b/source/package.h new file mode 100644 index 0000000..42c453a --- /dev/null +++ b/source/package.h @@ -0,0 +1,63 @@ +#ifndef PACKAGE_H_ +#define PACKAGE_H_ + +#include +#include +#include +#include "buildinfo.h" +#include "component.h" + +class Builder; +class Package; + +class PackageRef +{ +public: + PackageRef(Builder &, const std::string &); + Package *get_package(); +private: + Builder &builder; + std::string name; + Package *package; +}; + +class Package +{ +public: + class Loader: public Msp::Parser::Loader + { + public: + Loader(Package &); + Package &get_object() { return pkg; } + ~Loader(); + private: + Package &pkg; + + void require(const std::string &); + void program(const std::string &); + void library(const std::string &); + }; + + Package(Builder &, const std::string &, const Msp::Path::Path &); + Package(Builder &, const std::string &, const std::list &); + const std::string &get_name() const { return name; } + const Msp::Path::Path &get_source() const { return source; } + const ComponentList &get_components() const { return components; } + bool get_buildable() const { return buildable; } + void resolve_refs(); + + static Package *create(Builder &, const std::string &); +private: + Builder &builder; + std::string name; + std::string version; + std::string description; + std::list requires; + BuildInfo build_info; + BuildInfo export_binfo; + Msp::Path::Path source; + bool buildable; + ComponentList components; +}; + +#endif diff --git a/source/sourcefile.cpp b/source/sourcefile.cpp new file mode 100644 index 0000000..55910a6 --- /dev/null +++ b/source/sourcefile.cpp @@ -0,0 +1,34 @@ +#include +#include +#include "builder.h" +#include "component.h" +#include "sourcefile.h" + +using namespace std; +using namespace Msp; + +SourceFile::SourceFile(Builder &b, const Component *c, const string &n): + Target(b, c?&c->get_package():0, n), + comp(c) +{ } + +void SourceFile::find_depends() +{ + ifstream in(name.c_str()); + if(!in) return; + + Regex r_include("^[ \t]*#include[ \t]+([\"<].*)[\">]"); + + string line; + while(getline(in, line)) + if(RegMatch match=r_include.match(line)) + includes.push_back(match[1].str()); + + string path=name.substr(0, name.rfind('/')); + for(list::iterator i=includes.begin(); i!=includes.end(); ++i) + { + Target *hdr=builder.get_header(*i, path, comp->get_build_info().incpath); + if(hdr) + add_depend(hdr); + } +} diff --git a/source/sourcefile.h b/source/sourcefile.h new file mode 100644 index 0000000..962c575 --- /dev/null +++ b/source/sourcefile.h @@ -0,0 +1,19 @@ +#ifndef SOURCEFILE_H_ +#define SOURCEFILE_H_ + +#include "target.h" + +class Component; + +class SourceFile: public Target +{ +public: + SourceFile(Builder &, const Component *, const std::string &); + void find_depends(); + const char *get_type() const { return "SourceFile"; } +private: + const Component *comp; + std::list includes; +}; + +#endif diff --git a/source/target.cpp b/source/target.cpp new file mode 100644 index 0000000..481d2f4 --- /dev/null +++ b/source/target.cpp @@ -0,0 +1,47 @@ +#include "builder.h" +#include "target.h" + +using namespace std; + +Target *TargetRef::get_target() +{ + if(!target) + target=builder.get_target(name); + return target; +} + +Target *Target::get_buildable_target() +{ + if(rebuild && ready_for_build && !building) + return this; + + for(list::iterator i=depends.begin(); i!=depends.end(); ++i) + { + Target *tgt=(*i)->get_buildable_target(); + if(tgt) + return tgt; + } + + return 0; +} + +void Target::add_depend(Target *dep) +{ + depends.push_back(dep); + dep->rdepends.push_back(this); +} + +Target::Target(Builder &b, const Package *p, const string &n): + builder(b), + package(p), + name(n), + building(false), + rebuild(false), + ready_for_build(false) +{ } + +void Target::mark_rebuild(const std::string &reason) +{ + rebuild=true; + rebuild_reason=reason; +} diff --git a/source/target.h b/source/target.h new file mode 100644 index 0000000..21135b0 --- /dev/null +++ b/source/target.h @@ -0,0 +1,50 @@ +#ifndef TARGET_H_ +#define TARGET_H_ + +#include +#include +#include + +class Builder; +class Package; +class Target; + +class TargetRef +{ +public: + TargetRef(Builder &b, const std::string &n): builder(b), name(n) { } + Target *get_target(); +private: + Builder &builder; + std::string name; + Target *target; +}; + +class Target +{ +public: + const std::string &get_name() const { return name; } + Target *get_buildable_target(); + bool get_rebuild() const { return rebuild; } + const std::string &get_rebuild_reason() const { return rebuild_reason; } + virtual void find_depends()=0; + void add_depend(Target *); + virtual const char *get_type() const=0; + virtual ~Target() { } +protected: + Builder &builder; + const Package *package; + std::string name; + bool building; + bool rebuild; + std::string rebuild_reason; + Msp::Time::TimeStamp mtime; + std::list depends; + std::list rdepends; + bool ready_for_build; + + Target(Builder &, const Package *, const std::string &); + void mark_rebuild(const std::string &); +}; + +#endif diff --git a/source/virtualtarget.h b/source/virtualtarget.h new file mode 100644 index 0000000..e388061 --- /dev/null +++ b/source/virtualtarget.h @@ -0,0 +1,14 @@ +#ifndef VIRTUALTARGET_H_ +#define VIRTUALTARGET_H_ + +#include "target.h" + +class VirtualTarget: public Target +{ +public: + VirtualTarget(Builder &b, const std::string &n): Target(b,0,n) { } + const char *get_type() const { return "VirtualTarget"; } + void find_depends() { } +}; + +#endif