root/trunk/rebuild/config.c

Revision 926, 11.1 kB (checked in by Gregor, 3 months ago)

rebuild/config.c: Allow general link flags in a pragma(link).

Line 
1 // Component to read configuration
2 // Copyright (c) 2007  Gregor Richards
3 // License for redistribution is by either the Artistic License
4 // in artistic.txt, or the GNU General Public License in gnu.txt
5 // or any later version.
6 // See the included readme.txt for details.
7
8 #include <iostream>
9 #include <set>
10 using namespace std;
11
12 extern "C" {
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <unistd.h>
17 }
18
19 #if __WIN32
20 #define WIN32_LEAN_AND_MEAN
21 #include <windows.h>
22 #else
23 #include <unistd.h>
24 #endif
25
26 #include "compile.h"
27 #include "config.h"
28 #include "mars.h"
29 #include "mem.h"
30 #include "root.h"
31 #include "whereami.h"
32
33 #define exists(x) (!access((x), F_OK))
34 #if __WIN32
35 #define DIRSEP "\\"
36 #else
37 #define DIRSEP "/"
38 #endif
39
40 Config masterConfig;
41
42 std::string compileFlags;
43 std::string linkFlags;
44 std::string liblinkFlags;
45 std::string shliblinkFlags;
46
47 void readConfigFile(const string &dir, const string &fname, string &versionFile);
48
49 void readConfig(char *argvz, const string &profile, bool generate)
50 {
51     // find where we're installed
52     char *dir, *file;
53     if (!whereAmI(argvz, &dir, &file)) {
54         cerr << "Could not determine installed location!" << endl;
55         exit(1);
56     }
57    
58     // while we have this data, set our libpath
59     global.libpath = (char *) mem.malloc(strlen(dir) + 8);
60     sprintf(global.libpath, "%s/.." DIRSEP "lib", dir);
61    
62     // then look for appropriate directories
63     string confdir;
64 #ifndef __WIN32
65     confdir = string(getenv("HOME")) + DIRSEP ".rebuild";
66     if (exists(confdir.c_str())) goto founddir;
67 #endif
68    
69     confdir = string(dir) + DIRSEP "rebuild.conf";
70     if (exists(confdir.c_str())) goto founddir;
71    
72     confdir = string(dir) + DIRSEP ".." DIRSEP "etc" DIRSEP "rebuild";
73     if (exists(confdir.c_str())) goto founddir;
74     
75 #ifndef __WIN32
76     confdir = "/etc/rebuild";
77     if (exists(confdir.c_str())) goto founddir;
78 #else
79     confdir = "C:\\rebuild.conf";
80     if (exists(confdir.c_str())) goto founddir;
81 #endif
82    
83     cerr << "Cannot find a rebuild configuration directory." << endl;
84     exit(1);
85    
86    
87 founddir:
88     // OK, now look for the profile
89     string conffile = confdir + DIRSEP + profile;
90     if (!exists(conffile.c_str())) {
91         // perhaps generate it
92         if (generate) {
93             system("rebuild_choosedc");
94             readConfig(argvz, profile, false);
95             return;
96         } else {
97             cerr << "Profile '" << profile << "' does not exist." << endl;
98             if (profile == "default") {
99                 cerr << "You may generate it by running rebuild_choosedc";
100 #ifndef __WIN32
101                 cerr << ", as root, if necessary" << endl;
102 #else
103                 cerr << ".exe" << endl;
104 #endif
105             }
106             exit(1);
107         }
108     }
109    
110     // OK, read it
111     string versionFile;
112     readConfigFile(confdir, conffile, versionFile);
113    
114     // now run the version tests
115     if (versionFile.length() <= 0) return;
116
117     // check with the target compiler by writing a test file
118     // FIXME: test file should be better named
119     FILE *tmpfile = fopen("rebuild_tmp.d", "w");
120     if (!tmpfile) {
121         perror("rebuild_tmp.d");
122         exit(1);
123     }
124                
125     // write the test file
126     fprintf(tmpfile, "%s", versionFile.c_str());
127     fclose(tmpfile);
128    
129     // get the compile line
130     string response;
131     bool useresponse;
132     string cline = compileCommand("rebuild_tmp.d", response, useresponse);
133    
134     // test it
135 #define VERTESTBUF 1024
136     char result[VERTESTBUF + 1];
137     result[VERTESTBUF] = '\0';
138     int i;
139     char *lastResult;
140    
141     if (readCommand(cline, result, VERTESTBUF) < 1) {
142         std::cerr << "Could not detect versions." << std::endl;
143         exit(1);
144     }
145    
146     // remove temporary files
147     remove("rebuild_tmp.d");
148     remove("rebuild_tmp.o");
149     remove("rebuild_tmp.obj");
150    
151     // then go result-by-result
152     lastResult = result;
153     int len = strlen(result);
154     for (i = 0; i <= len; i++) {
155         if (result[i] == '\r') {
156             result[i] = '\0';
157            
158         } else if (result[i] == '\n' ||
159                    result[i] == '\0') {
160             result[i] = '\0';
161            
162             // add a version
163             if (!global.params.versionids)
164                 global.params.versionids = new Array();
165             global.params.versionids->push(mem.strdup(lastResult));
166            
167             lastResult = result + i + 1;
168            
169         }
170     }
171 }
172
173 // read in a configuration file
174 void readConfigFile(const string &dir, const string &fname, string &versionFile)
175 {
176     string section = "";
177    
178     FILE *cfile = fopen(fname.c_str(), "r");
179     if (!cfile) {
180         cerr << "Failed to open " << fname << endl;
181         exit(1);
182     }
183    
184     // the read buffer
185 #define READBUFSIZ 1024
186     char readBuf[READBUFSIZ + 1];
187     readBuf[READBUFSIZ] = '\0';
188     int readLen;
189    
190     // read lines
191     while (!feof(cfile) && !ferror(cfile)) {
192         if (!fgets(readBuf, READBUFSIZ, cfile)) break;
193        
194         // strip off line ending
195         readLen = strlen(readBuf);
196         while (readLen > 0 &&
197                (readBuf[readLen - 1] == '\n' ||
198                 readBuf[readLen - 1] == '\r')) {
199             readLen--;
200             readBuf[readLen] = '\0';
201         }
202        
203         if (readLen == 0 ||
204             readBuf[0] == '#') continue;
205        
206         // if it's [...], it's a section
207         if (readBuf[0] == '[' &&
208             readBuf[readLen - 1] == ']') {
209             readBuf[readLen - 1] = '\0';
210             section = readBuf + 1;
211            
212         } else {
213             // separate it into setting=value
214             char *val;
215             if (val = strchr(readBuf, '=')) {
216                 *val = '\0';
217                 val++;
218            
219                 // set it or possibly recurse
220                 if (section == "" &&
221                     !strcmp(readBuf, "profile")) {
222                     // recurse into another profile
223                     string subprof = dir + DIRSEP + string(val);
224                     if (!exists(subprof.c_str())) {
225                         cerr << "Profile " << subprof << ", required by " << fname << " not found." << endl;
226                         exit(1);
227                     }
228                
229                     readConfigFile(dir, subprof, versionFile);
230                    
231                 } else if (section == "" &&
232                            !strcmp(readBuf, "version")) {
233                     // predefined version set
234                     if (!global.params.versionids)
235                         global.params.versionids = new Array();
236                     global.params.versionids->push(mem.strdup(val));
237                    
238                 } else if (section == "" &&
239                            !strcmp(readBuf, "noversion")) {
240                     if (!global.params.versionidsNot)
241                         global.params.versionidsNot = new Array();
242                     global.params.versionidsNot->push(mem.strdup(val));
243                    
244                 } else if (section == "" &&
245                            !strcmp(readBuf, "testversion")) {
246                     // add to the test
247                     versionFile += "version(";
248                     versionFile += val;
249                     versionFile += ") { pragma(msg, \"";
250                     versionFile += val;
251                     versionFile += "\"); }\n";
252                    
253                 } else {
254                     // set a value
255                     masterConfig[section][readBuf] = val;
256                
257                 }
258             }
259         }
260     }
261     fclose(cfile);
262 }
263
264 // Read from a command
265 int readCommand(string cmd, char *buf, int len)
266 {
267     int rd = -1;
268
269 #ifndef __WIN32
270     int ip[2], op[2];
271     if (pipe(ip) == -1 ||
272         pipe(op) == -1) {
273         perror("pipe");
274         return -1;
275     }
276    
277     int pid = fork();
278     if (pid == 0) {
279         // child, fork the process
280         dup2(ip[0], 0);
281         close(ip[1]);
282         dup2(op[1], 1);
283         dup2(op[1], 2);
284         close(op[0]);
285         system(cmd.c_str());
286         return -1;
287                    
288     } else if (pid == -1) {
289         // uh oh! Assume no
290         write(op[1], "n", 1);
291     }
292                
293     close(ip[0]);
294     close(op[1]);
295    
296     // read repeatedly until there's no data left
297     int cl = 0;
298     while ((rd = read(op[0], buf + cl, len - cl)) > 0)
299     {
300         cl += rd;
301     }
302     rd = cl;
303    
304     buf[rd] = '\0';
305                
306     close(ip[1]);
307     close(op[0]);
308                 
309 #else
310     // WIN32 version
311     HANDLE ip[2], op[2];
312                
313     SECURITY_ATTRIBUTES sa;
314     memset(&sa, 0, sizeof(sa));
315     sa.nLength = sizeof(SECURITY_ATTRIBUTES);
316     sa.bInheritHandle = 1;
317     CreatePipe(ip, ip + 1, &sa, 0);
318     CreatePipe(op, op + 1, &sa, 0);
319                
320     STARTUPINFOA si;
321     memset(&si, 0, sizeof(si));
322     si.cb = sizeof(STARTUPINFOA);
323     si.hStdInput = ip[0];
324     si.hStdOutput = op[1];
325     si.hStdError = op[1];
326     si.dwFlags = STARTF_USESTDHANDLES;
327                
328     PROCESS_INFORMATION pi;
329     memset(&pi, 0, sizeof(pi));
330                
331     // start the sub process
332     CreateProcess(NULL, (CHAR *) cmd.c_str(), NULL, NULL,
333                   1, 0, NULL, NULL, &si, &pi);
334     CloseHandle(ip[0]);
335     CloseHandle(op[1]);
336     CloseHandle(pi.hThread);
337                
338     // read repeatedly until there's no data left
339     int cl = 0;
340     do {
341         ReadFile(op[0], buf + cl, len - cl, (DWORD *) &rd, NULL);
342         if (rd > 0) cl += rd;
343     } while (rd > 0);
344     rd = cl;
345    
346     buf[rd] = '\0';
347    
348     CloseHandle(ip[1]);
349     CloseHandle(op[0]);
350 #endif
351    
352     return rd;
353 }
354
355 // Add a flag, with a default
356 void addFlag(std::string &to, const std::string &section, const std::string &flag,
357              const std::string &def, const std::string &inp, const std::string &out,
358              bool pre)
359 {
360     std::string setfl;
361     int varLoc;
362    
363     if (masterConfig.find(section) != masterConfig.end() &&
364         masterConfig[section].find(flag) != masterConfig[section].end())
365         setfl = masterConfig[section][flag] + " ";
366     else
367         setfl = def + " ";
368    
369     // now parse $i and $o
370    
371     // replace $i
372     while ((varLoc = setfl.find("$i", 0)) != string::npos) {
373         setfl = setfl.substr(0, varLoc) +
374             inp +
375             setfl.substr(varLoc + 2);
376     }
377    
378     // replace $o
379     while ((varLoc = setfl.find("$o", 0)) != string::npos) {
380         setfl = setfl.substr(0, varLoc) +
381             out +
382             setfl.substr(varLoc + 2);
383     }
384    
385     if (pre) {
386         to = " " + setfl + to;
387     } else {
388         to += " " + setfl;
389     }
390 }
391
392 // Add a library to linkFlags
393 void linkLibrary(const std::string &name)
394 {
395     static string last = "";
396    
397     // don't add the same one more than once in a row ...
398     if (last == name) return;
399     last = name;
400    
401     if (name.length() != 0 && name[0] == '-') {
402         // a general link flag
403         addFlag(linkFlags, "link", "flag", "$i", name.substr(1), "", true);
404         addFlag(liblinkFlags, "link", "flag", "$i", name.substr(1), "", true);
405         addFlag(shliblinkFlags, "link", "flag", "$i", name.substr(1), "", true);
406     } else {
407         addFlag(linkFlags, "link", "lib", "$i", name, "", true);
408         addFlag(liblinkFlags, "liblink", "lib", "$i", name, "", true);
409         addFlag(shliblinkFlags, "shliblink", "lib", "$i", name, "", true);
410     }
411 }
Note: See TracBrowser for help on using the browser.