summaryrefslogtreecommitdiffabout
Side-by-side diff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--include/sitecing/sitecing_exception.h29
-rw-r--r--lib/component_factory.cc3
2 files changed, 30 insertions, 2 deletions
diff --git a/include/sitecing/sitecing_exception.h b/include/sitecing/sitecing_exception.h
index bf475ac..cb5edd9 100644
--- a/include/sitecing/sitecing_exception.h
+++ b/include/sitecing/sitecing_exception.h
@@ -1,103 +1,132 @@
#ifndef __SITECING_SITECING_EXCEPTION_H
#define __SITECING_SITECING_EXCEPTION_H
#include <konforka/exception.h>
/**
* @file
* @brief The site-C-ing specific exception.
*/
namespace sitecing {
/**
+ * The comonent failed to link.
+ */
+ class link_error : public konforka::exception {
+ public:
+ /**
+ * The component path
+ */
+ string component_path;
+
+ /**
+ * @param w the message.
+ * @param cp component path.
+ */
+ link_error(const string& w,const string& cp)
+ : konforka::exception(NOCODEPOINT,w), component_path(cp) { }
+ /**
+ * @param fi the file name where the exception is thrown from.
+ * @param fu the function name where the exception originates from.
+ * @param l the line number where the exception originates from.
+ * @param w the message.
+ * @param cp component path.
+ */
+ link_error(const string& fi,const string& fu,int l,const string& w,const string& cp)
+ : konforka::exception(fi,fu,l,w), component_path(cp) { }
+ ~link_error() throw() { }
+ };
+
+ /**
* The component failed to compile.
*/
class compile_error : public konforka::exception {
public:
/**
* The component path
*/
string component_path;
/**
* @param w the message.
* @param cp component path.
*/
compile_error(const string& w,const string& cp)
: konforka::exception(NOCODEPOINT,w), component_path(cp) { }
/**
* @param whe point in code.
* @param wha the message.
* @param cp component path.
*/
compile_error(const string &whe,const string& wha,const string& cp)
: konforka::exception(whe,wha), component_path(cp) { }
/**
* @param fi the file name where the exception is thrown from.
* @param fu the function name where the exception originates from.
* @param l the line number where the exception originates from.
+ * @param w the message.
* @param cp component path.
*/
compile_error(const string &fi,const string& fu,int l,const string& w,const string& cp)
: konforka::exception(fi,fu,l,w), component_path(cp) { }
~compile_error() throw() { }
};
/**
* Failed to preprocess component source.
*/
class preprocessor_error : public konforka::exception {
public:
/**
* Component name.
*/
string component_name;
/**
* The line number of the source code where the error occured.
*/
int line_number;
/**
* @param fi file name where the exception originates from.
* @param fu the function name where the exception originates from.
* @param l the line number where the exception originate from.
* @param w the error message.
* @param cn the component name.
* @param ln the line of the component source where the error occured.
*/
preprocessor_error(const string& fi,const string& fu,int l,const string& w,const string& cn,int ln)
: konforka::exception(fi,fu,l,w), component_name(cn), line_number(ln) { }
/**
* @param fi file name where the exception originates from.
* @param fu the function name where the exception originates from.
* @param l the line number where the exception originate from.
* @param w the error message.
* @param cn the component name.
*/
preprocessor_error(const string& fi,const string& fu,int l,const string& w,const string& cn)
: konforka::exception(fi,fu,l,w), component_name(cn), line_number(-1) { }
/**
* @param fi file name where the exception originates from.
* @param fu the function name where the exception originates from.
* @param l the line number where the exception originate from.
* @param w the error message.
* @param ln the line of the component source where the error occured.
*/
preprocessor_error(const string& fi,const string& fu,int l,const string& w,int ln)
: konforka::exception(fi,fu,l,w), line_number(ln) { }
/**
* @param fi file name where the exception originates from.
* @param fu the function name where the exception originates from.
* @param l the line number where the exception originate from.
* @param w the error message.
*/
preprocessor_error(const string& fi,const string& fu,int l,const string& w)
: konforka::exception(fi,fu,l,w), line_number(-1) { }
~preprocessor_error() throw() {}
};
}
#endif /* __SITECING_SITECING_EXCEPTION_H */
diff --git a/lib/component_factory.cc b/lib/component_factory.cc
index a5ced6b..2a2eefe 100644
--- a/lib/component_factory.cc
+++ b/lib/component_factory.cc
@@ -1,322 +1,321 @@
#ifdef USE_PCH
#include "pch.h"
#else
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <iostream>
#include <fstream>
#include <stdexcept>
#include <vector>
using namespace std;
#include "sitecing/component_factory.h"
#include "sitecing/sitecing_util.h"
#include "sitecing/sitecing_parser.h"
#include "sitecing/sitecing_exception.h"
#endif
namespace sitecing {
static const char *pp_targets[] = { ".cc", ".h", ".imports", ".classname", ".baseclassname", ".ancestors", ".pp_stamp" };
static const char *cc_targets[] = { ".o", ".d" };
component_factory::component_factory(configuration& c)
: config(c),
root_source(normalize_path(c.root_source,strip_trailing_slash)+'/'),
root_intermediate(normalize_path(c.root_intermediate,strip_trailing_slash)+'/'),
root_so(normalize_path(c.root_so,strip_trailing_slash)+'/') {
}
void component_factory::get_dependencies(const string& dst,file_list_t& deps) {
deps.clear();
string dp = normalize_path(dst,strip_trailing_slash);
// source documents
try { // XXX: or just compare it off?
string noro = strip_prefix(dp,root_source);
return;
}catch(utility_no_affix& una) { }
// .so binaries
try {
string noso = strip_suffix(dp,".so");
string noro = strip_prefix(noso,root_so);
deps.push_back(root_intermediate+noro+".o");
config_options *co_so_deps = config.lookup_config(noro,config_options::flag_so_deps);
if(co_so_deps) {
for(list<string>::const_iterator i=co_so_deps->so_deps.begin();i!=co_so_deps->so_deps.end();++i)
deps.push_back(*i);
}
return;
}catch(utility_no_prefix& unp) {
throw konforka::exception(CODEPOINT,"component is outside of component root");
}catch(utility_no_suffix& uns) { }
try {
// preprocessor targets
string noro = strip_prefix(dp,root_intermediate);
for(int ppt=0;ppt<sizeof(pp_targets)/sizeof(*pp_targets);ppt++) {
try {
string nos = strip_suffix(noro,pp_targets[ppt]);
deps.push_back(root_source+nos); // depends on the source
ifstream imports((root_intermediate+nos+".imports").c_str(),ios::in);
if(imports.good()) {
string str;
while(!imports.eof()) {
imports >> str;
if(!str.empty())
deps.push_back(root_intermediate+str+".classname");
}
}
ifstream ancestors((root_intermediate+nos+".ancestors").c_str(),ios::in);
if(ancestors.good()) {
string str;
while(!ancestors.eof()) {
ancestors >> str;
if(!str.empty())
deps.push_back(root_intermediate+str+".classname");
}
}
config_options *co_intermediate_deps = config.lookup_config(nos,config_options::flag_intermediate_deps);
if(co_intermediate_deps) {
for(list<string>::const_iterator i=co_intermediate_deps->intermediate_deps.begin();i!=co_intermediate_deps->intermediate_deps.end();++i)
deps.push_back(*i);
}
return;
}catch(utility_no_suffix& uns) { }
}
// compiler targets
for(int cct=0;cct<sizeof(cc_targets)/sizeof(*cc_targets);cct++) {
try {
string nos = strip_suffix(noro,cc_targets[cct]);
deps.push_back(root_intermediate+nos+".cc");
config_options *co_cpp_deps = config.lookup_config(noro,config_options::flag_cpp_deps);
if( (!co_cpp_deps) || co_cpp_deps->cpp_deps) {
ifstream df((root_intermediate+noro+".d").c_str(),ios::in);
if(df.good()) {
string str;
while(!df.eof()) {
df >> str;
if(str.find_first_of("\\:")==string::npos)
deps.push_back(combine_path(config.root_source+nos,str));
}
}
}
// XXX: extra deps like IntermediateDeps?
}catch(utility_no_suffix& uns) { }
}
}catch(utility_no_prefix& unp) { }
}
bool component_factory::is_uptodate(const string& dst,file_list_t *deps) {
string dp = normalize_path(dst,strip_trailing_slash);
// XXX: or just compare it off, instead of throwing things around.
try {
string noro = strip_prefix(dp,root_intermediate);
for(int ppt=0;(ppt+1)<sizeof(pp_targets)/sizeof(*pp_targets);ppt++) {
try {
string nos = strip_suffix(noro,pp_targets[ppt]);
return file_factory::is_uptodate(root_intermediate+nos+".pp_stamp",deps);
}catch(utility_no_suffix& uns) { }
}
bool rv = file_factory::is_uptodate(dst,deps);
return rv;
}catch(utility_no_prefix& unp) { }
try {
strip_prefix(dp,root_so);
return file_factory::is_uptodate(dst,deps);
}catch(utility_no_prefix& unp) { }
return true;
}
void component_factory::build(const string& dst) {
string dp = normalize_path(dst,strip_trailing_slash);
// sources
try {
string noro = strip_prefix(dp,root_source);
// building the sources is left up to developer
return;
}catch(utility_no_prefix& unp) { }
// .so files
try {
string noso = strip_suffix(dp,".so");
string noro = strip_prefix(noso,root_so);
string o = root_intermediate+noro+".o";
if(access(o.c_str(),R_OK))
throw konforka::exception(CODEPOINT,string("can't access compiled component code (")+o+")");
make_path(dir_name(root_so+noro),0755);
file_lock lock_cc(root_intermediate+noro+".o.lock");
file_lock lock_so(root_so+noro+".so.lock");
int stdO = open((root_intermediate+noro+".ld.stdout").c_str(),O_CREAT|O_TRUNC|O_WRONLY,0664);
if(stdO<0)
throw konforka::exception(CODEPOINT,"failed to open/create linker stdout");
int stdE = open((root_intermediate+noro+".ld.stderr").c_str(),O_CREAT|O_TRUNC|O_WRONLY,0664);
if(stdE<0) {
close(stdO);
throw konforka::exception(CODEPOINT,"failed to open/create linker stderr");
}
list<string> args;
config_options *co_ld_flags = config.lookup_config(noro,config_options::flag_ld_flags);
if(co_ld_flags) {
args.insert(args.end(),co_ld_flags->ld_flags.begin(),co_ld_flags->ld_flags.end());
}
args.push_back("-shared");
args.push_back(o);
file_list_t ancestors;
get_ancestors(noro,ancestors);
for(file_list_t::const_iterator i=ancestors.begin();i!=ancestors.end();++i) {
string aso=root_so+*i+".so";
make(aso);
args.push_back(aso);
}
args.push_back("-o"); args.push_back(dp);
// TODO: "g++" configurable
int rv = execute("g++",args,stdO,stdE);
if(! (WIFEXITED(rv) && !WEXITSTATUS(rv)) )
- // TODO:TODO: linker_error
- throw compile_error(CODEPOINT,"failed to link component",noro);
+ throw link_error(CODEPOINT,"failed to link component",noro);
return;
}catch(utility_no_prefix& unp) {
throw konforka::exception(CODEPOINT,"component is outside of component root");
}catch(utility_no_suffix& uns) { }
try {
string noro = strip_prefix(dp,root_intermediate);
// compiler targets
for(int cct=0;cct<sizeof(cc_targets)/sizeof(*cc_targets);cct++) {
try {
string nos = strip_suffix(noro,cc_targets[cct]);
string cc = root_intermediate+nos+".cc";
string o = root_intermediate+nos+".o";
if(access(cc.c_str(),R_OK))
throw konforka::exception(CODEPOINT,string("can't access preprocessed component code (")+cc+")");
make_path(dir_name(cc),0755);
string pwd = dir_name(root_source+nos);
auto_chdir dir_changer(pwd);
file_lock lock_source(root_intermediate+nos+".lock");
file_lock lock_cc(root_intermediate+nos+".o.lock");
int stdO = open((root_intermediate+nos+".stdout").c_str(),O_CREAT|O_TRUNC|O_WRONLY,0664);
if(stdO<0)
throw konforka::exception(CODEPOINT,"failed to open/create compiler stdout");
int stdE = open((root_intermediate+nos+".stderr").c_str(),O_CREAT|O_TRUNC|O_WRONLY,0664);
if(stdE<0) {
close(stdO);
throw konforka::exception(CODEPOINT,"failed to open/create compiler's stderr");
}
list<string> args;
config_options *co_cpp_flags = config.lookup_config(nos,config_options::flag_cpp_flags);
if(co_cpp_flags) {
args.insert(args.end(),co_cpp_flags->cpp_flags.begin(),co_cpp_flags->cpp_flags.end());
}
// TODO: maybe move it to separare config option like CoreCPPFLags?
args.push_back("-I"+root_intermediate);
args.push_back("-I"+root_source);
args.push_back("-MD"); args.push_back("-MF"); args.push_back(root_intermediate+nos+".d");
args.push_back("-c");
args.push_back(cc);
args.push_back("-o"); args.push_back(o);
// TODO: "g++" configurable
int rv = execute("g++",args,stdO,stdE);
if(! (WIFEXITED(rv) && !WEXITSTATUS(rv)) )
throw compile_error(CODEPOINT,"failed to compile component",nos);
return;
}catch(utility_no_suffix& uns) { }
}
// preprocessor targets
for(int ppt=0;ppt<sizeof(pp_targets)/sizeof(*pp_targets);ppt++) {
try {
string nos = strip_suffix(noro,pp_targets[ppt]);
string src = root_source+nos;
if(access(src.c_str(),R_OK))
throw konforka::exception(CODEPOINT,string("can't access component source (")+src+")");
make_path(dir_name(root_intermediate+nos),0755);
file_lock lock(root_intermediate+nos+".lock");
sitecing_parser parser(*this);
config_options *co_skeleton = config.lookup_config(nos,config_options::flag_skeleton);
if(co_skeleton)
parser.skeleton = co_skeleton->skeleton;
static const char *id_chars = "abcdefghijklmnopqrstuvwxyz0123456789_ABCDEFGHIJKLMNOPQRSTUVWXYZ";
parser.class_name = normalize_path(nos,strip_leading_slash|strip_trailing_slash);
for(string::size_type illc = parser.class_name.find_first_not_of(id_chars);illc!=string::npos;illc=parser.class_name.find_first_not_of(id_chars,illc)) {
string::size_type lc = parser.class_name.find_first_of(id_chars,illc);
int n = ((lc==string::npos)?parser.class_name.length():lc)-illc;
parser.class_name.replace(illc,n,n,'_');
}
parser.class_name = "_SCC_"+parser.class_name;
parser.output_basename = root_intermediate+nos;
parser.component_basename = nos;
try {
parser.preprocess(src);
string sf = root_intermediate+nos+".pp_stamp";
ofstream sfs(sf.c_str(),ios::trunc|ios::out); // touch .pp_stamp
}catch(preprocessor_error& pe) {
pe.component_name = nos;
pe.see(CODEPOINT);
throw;
}
return;
}catch(utility_no_suffix& uns) { }
}
}catch(utility_no_prefix& unp) { }
cerr << "ignoring build request for " << dp << endl;
}
int component_factory::execute(const string& cmd, const list<string>& args,int stdo,int stde) {
// XXX: is it right that we do stdio/stderr tricks outside of the function?
cerr << "executing: " << cmd;
vector<const char*> argv(args.size()+2);
argv[0]=cmd.c_str();
int an = 1;
for(list<string>::const_iterator i=args.begin();i!=args.end();i++) {
cerr << " " << *i ;
argv[an++] = i->c_str();
}
cerr << endl;
argv[an++]=NULL;
pid_t pid = vfork();
if(pid==-1) {
close(stdo); close(stde);
throw konforka::exception(CODEPOINT,"failed to vfork()");
}
if(!pid) {
// child
if(dup2(stdo,1)!=1)
_exit(-1);
if(dup2(stde,2)!=2)
_exit(-1);
close(0);
execvp(cmd.c_str(),(char**)&argv.front());
_exit(-1);
}
// parent
close(stdo); close(stde);
int rv;
if(waitpid(pid,&rv,0)<0)
throw konforka::exception(CODEPOINT,"failed to waitpid()");
return rv;
}
string component_factory::get_classname(const string& component) {
string cn = root_intermediate+normalize_path(component,strip_trailing_slash|strip_leading_slash)+".classname";
make(cn);
ifstream ifs(cn.c_str());
if(!ifs.good())
throw konforka::exception(CODEPOINT,"failed to access component .classname");
ifs >> cn;
return cn;
}
void component_factory::get_ancestors(const string& component,file_list_t& rv) {
string cn = root_intermediate+normalize_path(component,strip_trailing_slash|strip_leading_slash)+".ancestors";
make(cn);
ifstream ifs(cn.c_str());
if(!ifs.good())
throw konforka::exception(CODEPOINT,string("failed to access component '")+component+"' .ancestors");
rv.clear();
while(!ifs.eof()) {
string a;
ifs >> a;
if(!a.empty())
rv.push_back(a);
}
}
}