summaryrefslogtreecommitdiffabout
path: root/lib/component_factory.cc
Unidiff
Diffstat (limited to 'lib/component_factory.cc') (more/less context) (show whitespace changes)
-rw-r--r--lib/component_factory.cc19
1 files changed, 13 insertions, 6 deletions
diff --git a/lib/component_factory.cc b/lib/component_factory.cc
index f8666dc..b8f5a16 100644
--- a/lib/component_factory.cc
+++ b/lib/component_factory.cc
@@ -1,175 +1,180 @@
1#ifdef USE_PCH 1#ifdef USE_PCH
2 #include "pch.h" 2 #include "pch.h"
3#else 3#else
4 #include <sys/types.h> 4 #include <sys/types.h>
5 #include <sys/stat.h> 5 #include <sys/stat.h>
6 #include <unistd.h> 6 #include <unistd.h>
7 #include <sys/wait.h> 7 #include <sys/wait.h>
8 #include <fcntl.h> 8 #include <fcntl.h>
9 #include <iostream> 9 #include <iostream>
10 #include <fstream> 10 #include <fstream>
11 #include <stdexcept> 11 #include <stdexcept>
12 #include <vector> 12 #include <vector>
13 using namespace std; 13 using namespace std;
14 #include "sitecing/component_factory.h" 14 #include "sitecing/component_factory.h"
15 #include "sitecing/sitecing_util.h" 15 #include "sitecing/sitecing_util.h"
16 #include "sitecing/sitecing_parser.h" 16 #include "sitecing/sitecing_parser.h"
17 #include "sitecing/sitecing_exception.h" 17 #include "sitecing/sitecing_exception.h"
18#endif 18#endif
19 19
20namespace sitecing { 20namespace sitecing {
21 21
22 static const char *pp_targets[] = { ".cc", ".h", ".imports", ".classname", ".baseclassname", ".ancestors" }; 22 static const char *pp_targets[] = { ".cc", ".h", ".imports", ".classname", ".baseclassname", ".ancestors", ".pp_stamp" };
23 static const char *cc_targets[] = { ".o", ".d" }; 23 static const char *cc_targets[] = { ".o", ".d" };
24 24
25 component_factory::component_factory(configuration& c) 25 component_factory::component_factory(configuration& c)
26 : config(c), 26 : config(c),
27 root_source(normalize_path(c.root_source,strip_trailing_slash)+'/'), 27 root_source(normalize_path(c.root_source,strip_trailing_slash)+'/'),
28 root_intermediate(normalize_path(c.root_intermediate,strip_trailing_slash)+'/'), 28 root_intermediate(normalize_path(c.root_intermediate,strip_trailing_slash)+'/'),
29 root_so(normalize_path(c.root_so,strip_trailing_slash)+'/') { 29 root_so(normalize_path(c.root_so,strip_trailing_slash)+'/') {
30 } 30 }
31 31
32 void component_factory::get_dependencies(const string& dst,file_list_t& deps) { 32 void component_factory::get_dependencies(const string& dst,file_list_t& deps) {
33 deps.clear(); 33 deps.clear();
34 string dp = normalize_path(dst,strip_trailing_slash); 34 string dp = normalize_path(dst,strip_trailing_slash);
35 // source documents 35 // source documents
36 try { // XXX: or just compare it off? 36 try { // XXX: or just compare it off?
37 string noro = strip_prefix(dp,root_source); 37 string noro = strip_prefix(dp,root_source);
38 return; 38 return;
39 }catch(utility_no_affix& una) { 39 }catch(utility_no_affix& una) {
40 } 40 }
41 // .so binaries 41 // .so binaries
42 try { 42 try {
43 string noso = strip_suffix(dp,".so"); 43 string noso = strip_suffix(dp,".so");
44 string noro = strip_prefix(noso,root_so); 44 string noro = strip_prefix(noso,root_so);
45 deps.push_back(root_intermediate+noro+".o"); 45 deps.push_back(root_intermediate+noro+".o");
46 config_options *co_so_deps = config.lookup_config(noro,config_options::flag_so_deps); 46 config_options *co_so_deps = config.lookup_config(noro,config_options::flag_so_deps);
47 if(co_so_deps) { 47 if(co_so_deps) {
48 for(list<string>::const_iterator i=co_so_deps->so_deps.begin();i!=co_so_deps->so_deps.end();++i) 48 for(list<string>::const_iterator i=co_so_deps->so_deps.begin();i!=co_so_deps->so_deps.end();++i)
49 deps.push_back(*i); 49 deps.push_back(*i);
50 } 50 }
51 return; 51 return;
52 }catch(utility_no_prefix& unp) { 52 }catch(utility_no_prefix& unp) {
53 throw konforka::exception(CODEPOINT,"component is outside of component root"); 53 throw konforka::exception(CODEPOINT,"component is outside of component root");
54 }catch(utility_no_suffix& uns) { 54 }catch(utility_no_suffix& uns) {
55 } 55 }
56 // preprocessor targets 56 // preprocessor targets
57 for(int ppt=0;ppt<sizeof(pp_targets)/sizeof(*pp_targets);ppt++) { 57 for(int ppt=0;ppt<sizeof(pp_targets)/sizeof(*pp_targets);ppt++) {
58 try { 58 try {
59 string nos = strip_suffix(dp,pp_targets[ppt]); 59 string nos = strip_suffix(dp,pp_targets[ppt]);
60 string noro = strip_prefix(nos,root_intermediate); 60 string noro = strip_prefix(nos,root_intermediate);
61 deps.push_back(root_source+noro); 61 deps.push_back(root_source+noro);
62 ifstream imports((root_intermediate+noro+".imports").c_str(),ios::in); 62 ifstream imports((root_intermediate+noro+".imports").c_str(),ios::in);
63 if(imports.good()) { 63 if(imports.good()) {
64 string str; 64 string str;
65 while(!imports.eof()) { 65 while(!imports.eof()) {
66 imports >> str; 66 imports >> str;
67 if(!str.empty()) 67 if(!str.empty())
68 deps.push_back(root_intermediate+str+".classname"); 68 deps.push_back(root_intermediate+str+".classname");
69 } 69 }
70 } 70 }
71 ifstream ancestors((root_intermediate+noro+".ancestors").c_str(),ios::in); 71 ifstream ancestors((root_intermediate+noro+".ancestors").c_str(),ios::in);
72 if(ancestors.good()) { 72 if(ancestors.good()) {
73 string str; 73 string str;
74 while(!ancestors.eof()) { 74 while(!ancestors.eof()) {
75 ancestors >> str; 75 ancestors >> str;
76 if(!str.empty()) 76 if(!str.empty())
77 deps.push_back(root_intermediate+str+".classname"); 77 deps.push_back(root_intermediate+str+".classname");
78 } 78 }
79 } 79 }
80 config_options *co_intermediate_deps = config.lookup_config(noro,config_options::flag_intermediate_deps); 80 config_options *co_intermediate_deps = config.lookup_config(noro,config_options::flag_intermediate_deps);
81 if(co_intermediate_deps) { 81 if(co_intermediate_deps) {
82 for(list<string>::const_iterator i=co_intermediate_deps->intermediate_deps.begin();i!=co_intermediate_deps->intermediate_deps.end();++i) 82 for(list<string>::const_iterator i=co_intermediate_deps->intermediate_deps.begin();i!=co_intermediate_deps->intermediate_deps.end();++i)
83 deps.push_back(*i); 83 deps.push_back(*i);
84 } 84 }
85 return; 85 return;
86 }catch(utility_no_affix& una) { 86 }catch(utility_no_affix& una) {
87 // do nothing. must be a cpp dependency. 87 // do nothing. must be a cpp dependency.
88 } 88 }
89 } 89 }
90 // compiler targets 90 // compiler targets
91 for(int cct=0;cct<sizeof(cc_targets)/sizeof(*cc_targets);cct++) { 91 for(int cct=0;cct<sizeof(cc_targets)/sizeof(*cc_targets);cct++) {
92 try { 92 try {
93 string nos = strip_suffix(dp,cc_targets[cct]); 93 string nos = strip_suffix(dp,cc_targets[cct]);
94 string noro = strip_prefix(nos,root_intermediate); 94 string noro = strip_prefix(nos,root_intermediate);
95 deps.push_back(root_intermediate+noro+".cc"); 95 deps.push_back(root_intermediate+noro+".cc");
96 config_options *co_cpp_deps = config.lookup_config(noro,config_options::flag_cpp_deps); 96 config_options *co_cpp_deps = config.lookup_config(noro,config_options::flag_cpp_deps);
97 if( (!co_cpp_deps) || co_cpp_deps->cpp_deps) { 97 if( (!co_cpp_deps) || co_cpp_deps->cpp_deps) {
98 ifstream df((root_intermediate+noro+".d").c_str(),ios::in); 98 ifstream df((root_intermediate+noro+".d").c_str(),ios::in);
99 if(df.good()) { 99 if(df.good()) {
100 string str; 100 string str;
101 while(!df.eof()) { 101 while(!df.eof()) {
102 df >> str; 102 df >> str;
103 if(str.find_first_of("\\:")==string::npos) 103 if(str.find_first_of("\\:")==string::npos)
104 deps.push_back(combine_path(config.root_source+noro,str)); 104 deps.push_back(combine_path(config.root_source+noro,str));
105 } 105 }
106 } 106 }
107 } 107 }
108 // XXX: extra deps like IntermediateDeps? 108 // XXX: extra deps like IntermediateDeps?
109 }catch(utility_no_affix& una) { 109 }catch(utility_no_affix& una) {
110 // do nothing. 110 // do nothing.
111 } 111 }
112 } 112 }
113 } 113 }
114 114
115 bool component_factory::is_uptodate(const string& dst,file_list_t *deps) { 115 bool component_factory::is_uptodate(const string& dst,file_list_t *deps) {
116 string dp = normalize_path(dst,strip_trailing_slash); 116 string dp = normalize_path(dst,strip_trailing_slash);
117 // XXX: or just compare it off, instead of throwing things around. 117 // XXX: or just compare it off, instead of throwing things around.
118 try { 118 try {
119 strip_prefix(dp,root_intermediate); 119 string noro = strip_prefix(dp,root_intermediate);
120 return file_factory::is_uptodate(dst,deps); 120 for(int ppt=0;(ppt+1)<sizeof(pp_targets)/sizeof(*pp_targets);ppt++) {
121 }catch(utility_no_prefix& unp) { 121 try {
122 string nos = strip_suffix(noro,pp_targets[ppt]);
123 return file_factory::is_uptodate(root_intermediate+nos+".pp_stamp",deps);
124 }catch(utility_no_suffix& uns) { }
122 } 125 }
126 bool rv = file_factory::is_uptodate(dst,deps);
127 return rv;
128 }catch(utility_no_prefix& unp) { }
123 try { 129 try {
124 strip_prefix(dp,root_so); 130 strip_prefix(dp,root_so);
125 return file_factory::is_uptodate(dst,deps); 131 return file_factory::is_uptodate(dst,deps);
126 }catch(utility_no_prefix& unp) { 132 }catch(utility_no_prefix& unp) { }
127 }
128 return true; 133 return true;
129 } 134 }
130 135
131 void component_factory::build(const string& dst) { 136 void component_factory::build(const string& dst) {
132 string dp = normalize_path(dst,strip_trailing_slash); 137 string dp = normalize_path(dst,strip_trailing_slash);
133 // sources 138 // sources
134 try { 139 try {
135 string noro = strip_prefix(dp,root_source); 140 string noro = strip_prefix(dp,root_source);
136 // building the sources is left up to developer 141 // building the sources is left up to developer
137 return; 142 return;
138 }catch(utility_no_prefix& unp) { 143 }catch(utility_no_prefix& unp) {
139 } 144 }
140 // .so files 145 // .so files
141 try { 146 try {
142 string noso = strip_suffix(dp,".so"); 147 string noso = strip_suffix(dp,".so");
143 string noro = strip_prefix(noso,root_so); 148 string noro = strip_prefix(noso,root_so);
144 string o = root_intermediate+noro+".o"; 149 string o = root_intermediate+noro+".o";
145 if(access(o.c_str(),R_OK)) 150 if(access(o.c_str(),R_OK))
146 throw konforka::exception(CODEPOINT,string("can't access compiled component code (")+o+")"); 151 throw konforka::exception(CODEPOINT,string("can't access compiled component code (")+o+")");
147 make_path(dir_name(root_so+noro),0755); 152 make_path(dir_name(root_so+noro),0755);
148 file_lock lock_cc(root_intermediate+noro+".o.lock"); 153 file_lock lock_cc(root_intermediate+noro+".o.lock");
149 file_lock lock_so(root_so+noro+".so.lock"); 154 file_lock lock_so(root_so+noro+".so.lock");
150 int stdO = open((root_intermediate+noro+".ld.stdout").c_str(),O_CREAT|O_TRUNC|O_WRONLY,0664); 155 int stdO = open((root_intermediate+noro+".ld.stdout").c_str(),O_CREAT|O_TRUNC|O_WRONLY,0664);
151 if(stdO<0) 156 if(stdO<0)
152 throw konforka::exception(CODEPOINT,"failed to open/create linker stdout"); 157 throw konforka::exception(CODEPOINT,"failed to open/create linker stdout");
153 int stdE = open((root_intermediate+noro+".ld.stderr").c_str(),O_CREAT|O_TRUNC|O_WRONLY,0664); 158 int stdE = open((root_intermediate+noro+".ld.stderr").c_str(),O_CREAT|O_TRUNC|O_WRONLY,0664);
154 if(stdE<0) { 159 if(stdE<0) {
155 close(stdO); 160 close(stdO);
156 throw konforka::exception(CODEPOINT,"failed to open/create linker stderr"); 161 throw konforka::exception(CODEPOINT,"failed to open/create linker stderr");
157 } 162 }
158 list<string> args; 163 list<string> args;
159 config_options *co_ld_flags = config.lookup_config(noro,config_options::flag_ld_flags); 164 config_options *co_ld_flags = config.lookup_config(noro,config_options::flag_ld_flags);
160 if(co_ld_flags) { 165 if(co_ld_flags) {
161 args.insert(args.end(),co_ld_flags->ld_flags.begin(),co_ld_flags->ld_flags.end()); 166 args.insert(args.end(),co_ld_flags->ld_flags.begin(),co_ld_flags->ld_flags.end());
162 } 167 }
163 args.push_back("-shared"); 168 args.push_back("-shared");
164 args.push_back(o); 169 args.push_back(o);
165 file_list_t ancestors; 170 file_list_t ancestors;
166 get_ancestors(noro,ancestors); 171 get_ancestors(noro,ancestors);
167 for(file_list_t::const_iterator i=ancestors.begin();i!=ancestors.end();++i) { 172 for(file_list_t::const_iterator i=ancestors.begin();i!=ancestors.end();++i) {
168 string aso=root_so+*i+".so"; 173 string aso=root_so+*i+".so";
169 make(aso); 174 make(aso);
170 args.push_back(aso); 175 args.push_back(aso);
171 } 176 }
172 args.push_back("-o"); args.push_back(dp); 177 args.push_back("-o"); args.push_back(dp);
173 // TODO: "g++" configurable 178 // TODO: "g++" configurable
174 int rv = execute("g++",args,stdO,stdE); 179 int rv = execute("g++",args,stdO,stdE);
175 if(! (WIFEXITED(rv) && !WEXITSTATUS(rv)) ) 180 if(! (WIFEXITED(rv) && !WEXITSTATUS(rv)) )
@@ -204,96 +209,98 @@ namespace sitecing {
204 } 209 }
205 list<string> args; 210 list<string> args;
206 config_options *co_cpp_flags = config.lookup_config(noro,config_options::flag_cpp_flags); 211 config_options *co_cpp_flags = config.lookup_config(noro,config_options::flag_cpp_flags);
207 if(co_cpp_flags) { 212 if(co_cpp_flags) {
208 args.insert(args.end(),co_cpp_flags->cpp_flags.begin(),co_cpp_flags->cpp_flags.end()); 213 args.insert(args.end(),co_cpp_flags->cpp_flags.begin(),co_cpp_flags->cpp_flags.end());
209 } 214 }
210 // TODO: maybe move it to separare config option like CoreCPPFLags? 215 // TODO: maybe move it to separare config option like CoreCPPFLags?
211 args.push_back("-I"+root_intermediate); 216 args.push_back("-I"+root_intermediate);
212 args.push_back("-I"+root_source); 217 args.push_back("-I"+root_source);
213 args.push_back("-MD"); args.push_back("-MF"); args.push_back(root_intermediate+noro+".d"); 218 args.push_back("-MD"); args.push_back("-MF"); args.push_back(root_intermediate+noro+".d");
214 args.push_back("-c"); 219 args.push_back("-c");
215 args.push_back(cc); 220 args.push_back(cc);
216 args.push_back("-o"); args.push_back(o); 221 args.push_back("-o"); args.push_back(o);
217 // TODO: "g++" configurable 222 // TODO: "g++" configurable
218 int rv = execute("g++",args,stdO,stdE); 223 int rv = execute("g++",args,stdO,stdE);
219 if(! (WIFEXITED(rv) && !WEXITSTATUS(rv)) ) 224 if(! (WIFEXITED(rv) && !WEXITSTATUS(rv)) )
220 throw compile_error(CODEPOINT,"failed to compile component",noro); 225 throw compile_error(CODEPOINT,"failed to compile component",noro);
221 return; 226 return;
222 }catch(utility_no_affix& una) { 227 }catch(utility_no_affix& una) {
223 // do nothing, not a compiler target 228 // do nothing, not a compiler target
224 } 229 }
225 } 230 }
226 // preprocessor targets 231 // preprocessor targets
227 for(int ppt=0;ppt<sizeof(pp_targets)/sizeof(*pp_targets);ppt++) { 232 for(int ppt=0;ppt<sizeof(pp_targets)/sizeof(*pp_targets);ppt++) {
228 try { 233 try {
229 string nos = strip_suffix(dp,pp_targets[ppt]); 234 string nos = strip_suffix(dp,pp_targets[ppt]);
230 string noro = strip_prefix(nos,root_intermediate); 235 string noro = strip_prefix(nos,root_intermediate);
231 string src = root_source+noro; 236 string src = root_source+noro;
232 if(access(src.c_str(),R_OK)) 237 if(access(src.c_str(),R_OK))
233 throw konforka::exception(CODEPOINT,string("can't access component source (")+src+")"); 238 throw konforka::exception(CODEPOINT,string("can't access component source (")+src+")");
234 make_path(dir_name(root_intermediate+noro),0755); 239 make_path(dir_name(root_intermediate+noro),0755);
235 file_lock lock(root_intermediate+noro+".lock"); 240 file_lock lock(root_intermediate+noro+".lock");
236 sitecing_parser parser(*this); 241 sitecing_parser parser(*this);
237 config_options *co_skeleton = config.lookup_config(noro,config_options::flag_skeleton); 242 config_options *co_skeleton = config.lookup_config(noro,config_options::flag_skeleton);
238 if(co_skeleton) 243 if(co_skeleton)
239 parser.skeleton = co_skeleton->skeleton; 244 parser.skeleton = co_skeleton->skeleton;
240 static const char *id_chars = "abcdefghijklmnopqrstuvwxyz0123456789_ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 245 static const char *id_chars = "abcdefghijklmnopqrstuvwxyz0123456789_ABCDEFGHIJKLMNOPQRSTUVWXYZ";
241 parser.class_name = normalize_path(noro,strip_leading_slash|strip_trailing_slash); 246 parser.class_name = normalize_path(noro,strip_leading_slash|strip_trailing_slash);
242 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)) { 247 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)) {
243 string::size_type lc = parser.class_name.find_first_of(id_chars,illc); 248 string::size_type lc = parser.class_name.find_first_of(id_chars,illc);
244 int n = ((lc==string::npos)?parser.class_name.length():lc)-illc; 249 int n = ((lc==string::npos)?parser.class_name.length():lc)-illc;
245 parser.class_name.replace(illc,n,n,'_'); 250 parser.class_name.replace(illc,n,n,'_');
246 } 251 }
247 parser.class_name = "_SCC_"+parser.class_name; 252 parser.class_name = "_SCC_"+parser.class_name;
248 parser.output_basename = nos; 253 parser.output_basename = nos;
249 parser.component_basename = noro; 254 parser.component_basename = noro;
250 try { 255 try {
251 parser.preprocess(src); 256 parser.preprocess(src);
257 string sf = root_intermediate+noro+".pp_stamp";
258 ofstream sfs(sf.c_str(),ios::trunc|ios::out); // touch .pp_stamp
252 }catch(preprocessor_error& pe) { 259 }catch(preprocessor_error& pe) {
253 pe.component_name = noro; 260 pe.component_name = noro;
254 pe.see(CODEPOINT); 261 pe.see(CODEPOINT);
255 throw; 262 throw;
256 } 263 }
257 return; 264 return;
258 }catch(utility_no_affix& una) { 265 }catch(utility_no_affix& una) {
259 // must be a crap from .d file 266 // must be a crap from .d file
260 } 267 }
261 } 268 }
262 cerr << "ignoring build request for " << dp << endl; 269 cerr << "ignoring build request for " << dp << endl;
263 } 270 }
264 271
265 int component_factory::execute(const string& cmd, const list<string>& args,int stdo,int stde) { 272 int component_factory::execute(const string& cmd, const list<string>& args,int stdo,int stde) {
266 // XXX: is it right that we do stdio/stderr tricks outside of the function? 273 // XXX: is it right that we do stdio/stderr tricks outside of the function?
267 cerr << "executing: " << cmd; 274 cerr << "executing: " << cmd;
268 vector<const char*> argv(args.size()+2); 275 vector<const char*> argv(args.size()+2);
269 argv[0]=cmd.c_str(); 276 argv[0]=cmd.c_str();
270 int an = 1; 277 int an = 1;
271 for(list<string>::const_iterator i=args.begin();i!=args.end();i++) { 278 for(list<string>::const_iterator i=args.begin();i!=args.end();i++) {
272 cerr << " " << *i ; 279 cerr << " " << *i ;
273 argv[an++] = i->c_str(); 280 argv[an++] = i->c_str();
274 } 281 }
275 cerr << endl; 282 cerr << endl;
276 argv[an++]=NULL; 283 argv[an++]=NULL;
277 pid_t pid = vfork(); 284 pid_t pid = vfork();
278 if(pid==-1) { 285 if(pid==-1) {
279 close(stdo); close(stde); 286 close(stdo); close(stde);
280 throw konforka::exception(CODEPOINT,"failed to vfork()"); 287 throw konforka::exception(CODEPOINT,"failed to vfork()");
281 } 288 }
282 if(!pid) { 289 if(!pid) {
283 // child 290 // child
284 if(dup2(stdo,1)!=1) 291 if(dup2(stdo,1)!=1)
285 _exit(-1); 292 _exit(-1);
286 if(dup2(stde,2)!=2) 293 if(dup2(stde,2)!=2)
287 _exit(-1); 294 _exit(-1);
288 close(0); 295 close(0);
289 execvp(cmd.c_str(),(char**)&argv.front()); 296 execvp(cmd.c_str(),(char**)&argv.front());
290 _exit(-1); 297 _exit(-1);
291 } 298 }
292 // parent 299 // parent
293 close(stdo); close(stde); 300 close(stdo); close(stde);
294 int rv; 301 int rv;
295 if(waitpid(pid,&rv,0)<0) 302 if(waitpid(pid,&rv,0)<0)
296 throw konforka::exception(CODEPOINT,"failed to waitpid()"); 303 throw konforka::exception(CODEPOINT,"failed to waitpid()");
297 return rv; 304 return rv;
298 } 305 }
299 306