1 // Test platform supportability and establish build configuration:
2 //
3 // Writes the configuration parameters to these two files:
4 //
5 // Configuration.Mod - settings to compile into the compiler binary
6 // Configuration.make - makefile variable settings for this configuration
7 //
8 // Derived from vocparam.c originally by J. Templ 23.6.95
9
10
11 #define O_VER 2.1.0 // Version number to be reported by compiler.
12 #define O_NAME voc // Compiler name used for binary, install dir and references in text.
13
14
15 #include "SYSTEM.h"
16
17
18 #ifdef _WIN32
19 #define strncasecmp _strnicmp
20 char* getcwd(char* buf, size_t size);
21 #else
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <fcntl.h>
25 #include <sys/utsname.h>
26 #include <unistd.h>
27 #endif
28
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <time.h>
32 #include <string.h>
33
34
fail(char * msg)35 void fail(char *msg) {fprintf(stderr, "Error: %s\n", msg); exit(1);}
assert(int truth,char * complaint)36 void assert(int truth, char *complaint) {if (!truth) fail(complaint);}
37
38
39
40
41 char builddate[256];
42 char installdir[256];
43 char versionstring[256];
44 char osrelease[1024];
45 char cwd[1024];
46 char libspec[1024];
47
48 #define macrotostringhelper(s) #s
49 #define macrotostring(s) macrotostringhelper(s)
50 char *version = macrotostring(O_VER);
51 char *objext = ".o";
52 char *objflag = " -o ";
53 char *linkflags = " -L\"";
54 char *libext = "";
55 char *oname = NULL; // From O_NAME env var if present, or O_NAME macro otherwise.
56 char *dynext = ".so";
57 char *dataModel = NULL;
58 char *compiler = NULL;
59 char *cc = NULL;
60 char *os = NULL;
61 char *platform = NULL;
62 char *binext = NULL;
63 char *staticlink = NULL; // Static compilation option - none on darwin / windows.
64 int alignment = 0;
65 int addressSize = 0;
66 int intsize = 0;
67 int bsd = 0;
68 int termux = 0;
69 int bootstrap = 0; // 1 iff generating a bootstrap compiler.
70
71
72
ParseOsRelease(FILE * fd)73 void ParseOsRelease(FILE *fd) {
74 while (fgets(osrelease, sizeof(osrelease), fd) != NULL) {
75 if (strncasecmp(osrelease, "id=", 3) == 0) {
76 int i=3;
77 while (osrelease[i] == '"') {i++;}
78 int j=i;
79 while (osrelease[j] > '"') {j++;}
80 if (j>i) {
81 osrelease[j] = 0;
82 os = osrelease + i;
83 }
84 break;
85 }
86 }
87 fclose(fd);
88 }
89
90
determineLinuxVariant()91 void determineLinuxVariant() {
92 FILE *fd = NULL;
93 os = "linux";
94
95 if ((fd = fopen("/etc/os-release", "r"))) {ParseOsRelease(fd); return;}
96 // Hack for centos without /etc/os-release
97 if ((fd = fopen("/etc/centos-release", "r"))) {os = "centos"; fclose(fd); return;}
98 // Hack to detect running in termux in android
99 if ((fd = fopen("/data/data/com.termux/files/usr/bin/bash", "r"))) {os = "termux"; staticlink = ""; termux = 1; fclose(fd); return;}
100 }
101
102
determineOS()103 void determineOS() {
104 #ifdef _WIN32
105 os = "windows"; platform = "windows"; binext = ".exe"; staticlink = "";
106 #else
107 os = "unknown"; platform = "unix"; binext = ""; staticlink = " -static";
108
109 struct utsname sys;
110 if (uname(&sys)<0) fail("Couldn't get sys name - uname() failed.");
111
112 if (strncasecmp(sys.sysname, "cygwin", 6) == 0) {os = "cygwin"; binext = ".exe";}
113 else if (strncasecmp(sys.sysname, "linux", 5) == 0) {determineLinuxVariant();}
114 else if (strncasecmp(sys.sysname, "dragonfly", 9) == 0) {os = "dragonfly"; bsd = 1;}
115 else if (strncasecmp(sys.sysname, "freebsd", 5) == 0) {os = "freebsd"; bsd = 1;}
116 else if (strncasecmp(sys.sysname, "openbsd", 5) == 0) {os = "openbsd"; bsd = 1;}
117 else if (strncasecmp(sys.sysname, "darwin", 5) == 0) {os = "darwin"; staticlink = ""; dynext = ".dylib";}
118 else {
119 fprintf(stderr, "\n\n** Unrecognised utsname.sysname '%s' returned by uname().\n", sys.sysname);
120 fprintf(stderr, "** Please add a test for this OS in src/buildtools/configure.c\n");
121 fprintf(stderr, "** in function determineOS() near line %d.\n\n", __LINE__-3);
122 fail("Unrecognised OS architecture name (sysname) returned by uname.");
123 }
124 #endif
125 }
126
127 #define optimize "" // " -O1"
128
determineCCompiler()129 void determineCCompiler() {
130 snprintf(libspec, sizeof(libspec), " -l%s", oname);
131 #if defined(__MINGW32__)
132 compiler = "mingw";
133 if (sizeof (void*) == 4) {
134 cc = "i686-w64-mingw32-gcc -g" optimize;
135 } else {
136 cc = "x86_64-w64-mingw32-gcc -g" optimize;
137 }
138 #elif defined(__clang__)
139 compiler = "clang";
140 cc = "clang -fPIC -g" optimize;
141 #elif defined(__TINYC__)
142 compiler = "tcc";
143 cc = "tcc -g";
144 staticlink = "";
145 #elif defined(__GNUC__)
146 compiler = "gcc";
147 if (strncasecmp(os, "cygwin", 6) == 0) {
148 // Avoid cygwin specific warning that -fPIC is ignored.
149 cc = "gcc -g" optimize;
150 } else {
151 cc = "gcc -fPIC -g" optimize;
152 }
153 #elif defined(_MSC_VER)
154 compiler = "msc";
155 cc = "cl /nologo";
156 objext = ".obj";
157 objflag = " -Fe";
158 linkflags = " -link -libpath:\"";
159 snprintf(libspec, sizeof(libspec), " lib%s", oname);
160 libext = ".lib";
161 #else
162 fail("Unrecognised C compiler.");
163 #endif
164 }
165
166
167
determineInstallDirectory()168 void determineInstallDirectory() {
169 if (bootstrap) {
170 installdir[0] = 0;
171 } else {
172 char *env = getenv("INSTALLDIR");
173 if (env) {
174 strncpy(installdir, env, sizeof(installdir));
175 } else {
176 #if defined(_MSC_VER) || defined(__MINGW32__)
177 if (sizeof (void*) == 8) {
178 snprintf(installdir, sizeof(installdir), "%s\\%s", getenv("ProgramFiles"), oname);
179 } else {
180 snprintf(installdir, sizeof(installdir), "%s\\%s", getenv("ProgramFiles(x86)"), oname);
181 }
182 #if defined(__MINGW32__)
183 int i; for(i=0; installdir[i]; i++) if (installdir[i] == '\\') installdir[i] = '/';
184 #endif
185 #else
186 if (bsd) {
187 snprintf(installdir, sizeof(installdir), "/usr/local/share/%s", oname);
188 } else if (termux) {
189 snprintf(installdir, sizeof(installdir), "/data/data/com.termux/files/opt/%s", oname);
190 } else {
191 snprintf(installdir, sizeof(installdir), "/opt/%s", oname);
192 }
193 #endif
194 }
195 }
196 }
197
198
199
200
determineBuildDate()201 void determineBuildDate() {
202 time_t t = time(0);
203 strftime(builddate, sizeof(builddate), "%Y/%m/%d", localtime(&t));
204 }
205
206
207
208 struct {char ch; CHAR x;} c;
209 struct {char ch; BOOLEAN x;} b;
210 //struct {char ch; SHORTINT x;} si;
211 //struct {char ch; INTEGER x;} i;
212 //struct {char ch; LONGINT x;} li;
213 //struct {char ch; SET x;} s;
214 struct {char ch; REAL x;} r;
215 struct {char ch; LONGREAL x;} lr;
216 struct {char ch; void* x;} p;
217 struct {char ch; void (*x)();} f;
218 struct {char ch; int x;} in;
219 struct {char ch; long x;} lo;
220 struct {char ch; long long x;} ll;
221 struct {char ch; char x[1];} a1;
222 struct {char ch; char x[2];} a2;
223 struct {char ch; char x[4];} a4;
224 struct {char ch; char x[8];} a8;
225
226 struct s1 {char ch;}; struct {char ch; struct s1 x;} s1;
227 struct s2 {char ch[2];}; struct {char ch; struct s2 x;} s2;
228 struct s4 {char ch[4];}; struct {char ch; struct s4 x;} s4;
229 struct s8 {char ch[8];}; struct {char ch; struct s8 x;} s8;
230
231 struct {char ch;} rec0;
232 struct {char x[65];} rec2;
233
234
235
236
237 // Pass any parameter to configure and it will report sizes and alignments
238 // instead of generating configuration files.
239
ReportSizesAndAlignments()240 void ReportSizesAndAlignments() {
241 printf("Type Size Align\n");
242 printf("CHAR %4zd %4td\n", sizeof(CHAR), (char*)&c.x - (char*)&c);
243 printf("BOOLEAN %4zd %4td\n", sizeof(BOOLEAN), (char*)&b.x - (char*)&b);
244 //printf("SHORTINT %4zd %4td\n", sizeof(SHORTINT), (char*)&si.x - (char*)&si);
245 //printf("INTEGER %4zd %4td\n", sizeof(INTEGER), (char*)&i.x - (char*)&i);
246 //printf("LONGINT %4zd %4td\n", sizeof(LONGINT), (char*)&li.x - (char*)&li);
247 //printf("SET %4zd %4td\n", sizeof(SET), (char*)&s.x - (char*)&s);
248 printf("REAL %4zd %4td\n", sizeof(REAL), (char*)&r.x - (char*)&r);
249 printf("LONGREAL %4zd %4td\n", sizeof(LONGREAL), (char*)&lr.x - (char*)&lr);
250 printf("void* %4zd %4td\n", sizeof(void*), (char*)&p.x - (char*)&p);
251 printf("int %4zd %4td\n", sizeof(int), (char*)&in.x - (char*)&in);
252 printf("long %4zd %4td\n", sizeof(long), (char*)&lo.x - (char*)&lo);
253 printf("long long %4zd %4td\n", sizeof(long long), (char*)&ll.x - (char*)&ll);
254 printf("char[1] %4zd %4td\n", sizeof(a1.x), (char*)&a1.x - (char*)&a1);
255 printf("char[2] %4zd %4td\n", sizeof(a2.x), (char*)&a2.x - (char*)&a2);
256 printf("char[4] %4zd %4td\n", sizeof(a4.x), (char*)&a4.x - (char*)&a4);
257 printf("char[8] %4zd %4td\n", sizeof(a8.x), (char*)&a8.x - (char*)&a8);
258 printf("struct s1 %4zd %4td\n", sizeof(struct s1), (char*)&s1.x - (char*)&s1);
259 printf("struct s2 %4zd %4td\n", sizeof(struct s2), (char*)&s2.x - (char*)&s2);
260 printf("struct s4 %4zd %4td\n", sizeof(struct s4), (char*)&s4.x - (char*)&s4);
261 printf("struct s8 %4zd %4td\n", sizeof(struct s8), (char*)&s8.x - (char*)&s8);
262 }
263
264
265
266 #define MIN(a,b) (((a)<(b)) ? (a) : (b))
267
determineCDataModel()268 void determineCDataModel() {
269 addressSize = sizeof(void*);
270 alignment = (char*)&lr.x - (char*)&lr; // Base alignment measure on largest type.
271
272 if (addressSize == 4 && sizeof(int) == 4) dataModel = "ILP32"; // Unix/Linux and modern Win32
273 else if (addressSize == 8 && sizeof(long) == 4) dataModel = "LLP64"; // Windows/mingw 64 bit
274 else if (addressSize == 8 && sizeof(long) == 8) dataModel = "LP64"; // Unix/Linux 64 bit
275 else fail("Unsupported combination of address size and int/long size.");
276
277 // Check for supported address sie and alignment
278
279 if (addressSize == 4) {
280 assert(alignment == 4 || alignment == 8, "Aligment neither 4 nor 8 when address size is 4.");
281 } else {
282 assert(addressSize == 8, "Address size neither 4 nor 8.");
283 assert(alignment == 8, "Alignemnt not 8 when address size is 8.");
284 }
285
286 // Define 'LARGE' to get 32 bit INTEGER and 64 bit LONGINT even on 32 bit systems.
287 // Note that plenty of the library source files do not expect this.
288
289 #ifdef LARGE
290 intsize = 4;
291 #else
292 intsize = (addressSize == 4) ? 2 : 4;
293 #endif
294 }
295
296
297
298
testSystemDotH()299 void testSystemDotH() {
300 /* test the __ASHR macro */
301 assert(__ASHR(-1, 1) == -1, "ASH(-1, -1) # -1.");
302 assert(__ASHR(-2, 1) == -1, "ASH(-2, -1) # -1.");
303 assert(__ASHR(0, 1) == 0, "ASH(0, 1) # 0.");
304 assert(__ASHR(1, 1) == 0, "ASH(1, 1) # 0.");
305 assert(__ASHR(2, 1) == 1, "ASH(2, 1) # 1.");
306
307 /* test the __SETRNG macro */
308 long x = 0;
309 long y;
310 y=31; assert(__SETRNG(x, y, 32) == -1, "SETRNG(0, MAX(SET), 32) != -1.");
311 y=63; assert(__SETRNG(x, y, 64) == -1, "SETRNG(0, MAX(SET), 32) != -1.");
312 // long y = sizeof(SET)*8 - 1;
313 // if (sizeof(SET) == 4)
314 // assert(__SETRNG(x, y, 32) == -1, "SETRNG(0, MAX(SET)) != -1.");
315 // else
316 // assert(__SETRNG(x, y, 64) == -1, "SETRNG(0, MAX(SET)) != -1.");
317
318 /* test string comparison for extended ascii */
319 {char a[10], b[10];
320 a[0] = (CHAR)128; a[1] = 0;
321 b[0] = 0;
322 assert(__STRCMP(a, b) >= 0, "__STRCMP(a, b) with extended ascii charcters; should be unsigned.");
323 }
324
325 // Check the sizes of the Oberon basic types as defined in SYSTEM.h.
326 // By design all but INTEGER and LONGINT are fixed across all supported platfroms.
327
328 assert(sizeof(CHAR) == 1, "Size of CHAR not 1.");
329 assert(sizeof(BOOLEAN) == 1, "Size of BOOLEAN not 1.");
330 //assert(sizeof(SHORTINT) == 1, "Size of SHORTINT not 1.");
331 //assert(sizeof(INTEGER) == 2
332 // || sizeof(INTEGER) == 4, "Size of INTEGER neither 2 nor 4 bytes.");
333 //assert(sizeof(LONGINT) == 4
334 // || sizeof(LONGINT) == 8, "Size of LONGINT neither 4 nor 8 bytes.");
335 //assert(sizeof(SET) == sizeof(LONGINT), "Size of SET differs from size of LONGINT.");
336 assert(sizeof(REAL) == 4, "Size of REAL not 4 bytes.");
337 assert(sizeof(LONGREAL) == 8, "Size of LONGREAL not 8 bytes.");
338 assert(sizeof(f.x) == sizeof(p.x), "Size of function pointer differs from size of data pointer.");
339
340 assert((alignment == 4) || (alignment == 8), "Alignment of LONGINT neither 4 nor 8 bytes.");
341
342 assert(((char*)&c.x - (char*)&c) == 1, "Alignment of CHAR not 1.");
343 assert(((char*)&b.x - (char*)&b) == 1, "Alignment of BOOLEAN not 1.");
344 //assert(((char*)&si.x - (char*)&si) == 1, "Alignment of SHORTINT not 1.");
345 //assert(((char*)&i.x - (char*)&i) == 4, "Alignment of INTEGER not 4 bytes.");
346 assert(((char*)&r.x - (char*)&r) == 4, "Alignment of REAL not 4 bytes.");
347 assert(((char*)&lr.x - (char*)&lr) >= 4, "Alignment of LONGREAL less than 4 bytes.");
348 //assert(((char*)&s.x - (char*)&s) == MIN(alignment, sizeof(SET)), "Alignment of SET differs from alignmnet of LONGINT.");
349 assert(((char*)&p.x - (char*)&p) == addressSize, "Alignment of data pointer differs from address size.");
350 assert(((char*)&f.x - (char*)&f) == addressSize, "Alignment of data pointer differs from address size.");
351 assert(((char*)&lr.x - (char*)&lr) == ((char*)&ll.x - (char*)&ll), "Alignment of LONGREAL differs from alignment of long long.");
352
353 assert(sizeof(rec0) == 1, "CHAR wrapped in record aligns differently to CHAR alone.");
354 assert(sizeof(rec2) == 65, "CHAR array wrapped in record aligns differently to CHAR array alone.");
355
356 //assert(sizeof(LONGINT) >= sizeof(p.x), "LONGINT should have at least the same size as data pointers.");
357 //assert(sizeof(LONGINT) >= sizeof(f.x), "LONGINT should have at least the same size as function pointers.");
358
359 if (((sizeof(rec2)==65) == (sizeof(rec0)==1)) && ((sizeof(rec2)-64) != sizeof(rec0)))
360 printf("error: unsupported record layout sizeof(rec0) = %lu sizeof(rec2) = %lu\n", (long)sizeof(rec0), (long)sizeof(rec2));
361
362 x = 1;
363 assert(*(char*)&x == 1, "C compiler does not store multibyte numeric values in little-endian order.");
364 }
365
366
367
368
writeMakeParameters()369 void writeMakeParameters() {
370 FILE *fd = fopen("Configuration.Make", "w");
371 if (fd == NULL) fail("Couldn't create Configuration.make.");
372 fprintf(fd, "OLANGDIR=%s\n", cwd);
373 fprintf(fd, "COMPILER=%s\n", compiler);
374 fprintf(fd, "OS=%s\n", os);
375 fprintf(fd, "VERSION=%s\n", version);
376 fprintf(fd, "ONAME=%s\n", oname);
377 fprintf(fd, "DATAMODEL=%s\n", dataModel);
378 fprintf(fd, "ADRSIZE=%d\n", addressSize);
379 fprintf(fd, "ALIGNMENT=%d\n", alignment);
380 fprintf(fd, "INSTALLDIR=%s\n", installdir);
381 fprintf(fd, "PLATFORM=%s\n", platform);
382 fprintf(fd, "BINEXT=%s\n", binext);
383 fprintf(fd, "DYNEXT=%s\n", dynext);
384 fprintf(fd, "COMPILE=%s\n", cc);
385 fprintf(fd, "STATICLINK=%s\n", staticlink);
386 fclose(fd);
387 }
388
389
390
391
writeConfigurationMod()392 void writeConfigurationMod() {
393 FILE *fd = fopen("Configuration.Mod", "w");
394 if (fd == NULL) fail("Couldn't create Configuration.Mod.");
395
396 fprintf(fd, "MODULE Configuration;\n");
397 fprintf(fd, "CONST\n");
398 fprintf(fd, " name* = '%s';\n", oname);
399 fprintf(fd, " objext* = '%s';\n", objext);
400 fprintf(fd, " objflag* = '%s';\n", objflag);
401 fprintf(fd, " linkflags* = '%s';\n", linkflags);
402 fprintf(fd, " libspec* = '%s';\n", libspec);
403 fprintf(fd, " libext* = '%s';\n", libext);
404 fprintf(fd, " os* = '%s';\n", os);
405 fprintf(fd, " compiler* = '%s';\n", compiler);
406 fprintf(fd, " compile* = '%s';\n", cc);
407 fprintf(fd, " installdir* = '%s';\n", installdir);
408 fprintf(fd, " staticLink* = '%s';\n", staticlink);
409 fprintf(fd, "VAR\n");
410 fprintf(fd, " versionLong-: ARRAY %d OF CHAR;\n", (int)strnlen(versionstring, 100)+1);
411 fprintf(fd, "BEGIN\n");
412 fprintf(fd, " versionLong := '%s';\n", versionstring);
413 fprintf(fd, "END Configuration.\n");
414
415 fclose(fd);
416 }
417
418
419
420
main(int argc,char * argv[])421 int main(int argc, char *argv[])
422 {
423 // Make sure SYSTEM.h has set up our core data types correctly.
424 assert(sizeof(INT8) == 1, "sizeof(INT8) is not 1.");
425 assert(sizeof(INT16) == 2, "sizeof(INT16) is not 2.");
426 assert(sizeof(INT32) == 4, "sizeof(INT32) is not 4.");
427 assert(sizeof(INT64) == 8, "sizeof(INT64) is not 8.");
428
429 oname = getenv("ONAME"); if (!oname) oname = macrotostring(O_NAME);
430
431 if (argc>1) {
432 if (strncasecmp(argv[1], "rep", 3) == 0) {
433 ReportSizesAndAlignments();
434 exit(0);
435 } else {
436 bootstrap = 1;
437 }
438 }
439
440 getcwd(cwd, sizeof(cwd));
441 int i; for (i=0; cwd[i]; i++) if (cwd[i]=='\\') cwd[i]='/';
442
443 determineOS();
444 determineCCompiler();
445 determineCDataModel();
446 determineBuildDate();
447 determineInstallDirectory();
448
449 testSystemDotH();
450
451 if (bootstrap) {
452 snprintf(versionstring, sizeof(versionstring),
453 "%s [%s]. Bootstrapping compiler for address size %d, alignment %d.",
454 version, builddate, addressSize, alignment);
455 } else {
456 snprintf(versionstring, sizeof(versionstring),
457 "%s [%s] for %s %s on %s",
458 version, builddate, compiler, dataModel, os);
459 }
460
461 writeConfigurationMod();
462 writeMakeParameters();
463
464 printf("Configuration: %s\n", versionstring);
465 return 0;
466 }
467