1 /* @(#)archconf.c 1.35 20/04/04 Copyright 1996-2020 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static UConst char sccsid[] =
5 "@(#)archconf.c 1.35 20/04/04 Copyright 1996-2020 J. Schilling";
6 #endif
7 /*
8 * Make program
9 * Architecture autoconfiguration support
10 *
11 * Copyright (c) 1996-2020 by J. Schilling
12 */
13 /*
14 * The contents of this file are subject to the terms of the
15 * Common Development and Distribution License, Version 1.0 only
16 * (the "License"). You may not use this file except in compliance
17 * with the License.
18 *
19 * See the file CDDL.Schily.txt in this distribution for details.
20 * A copy of the CDDL is also available via the Internet at
21 * http://www.opensource.org/licenses/cddl1.txt
22 *
23 * When distributing Covered Code, include this CDDL HEADER in each
24 * file and include the License file CDDL.Schily.txt from this distribution.
25 */
26
27 #include <schily/stdio.h>
28 #include <schily/standard.h>
29 #include <schily/unistd.h>
30 #include <schily/string.h>
31 #include <schily/ctype.h>
32
33 #include <schily/hostname.h>
34 #include <schily/utsname.h>
35 #include <schily/systeminfo.h>
36
37 #include <schily/schily.h>
38 #include "make.h"
39
40 #ifdef HAVE_SYS_SYSCTL_H
41 #include <schily/types.h>
42 #include <schily/param.h>
43 #include <sys/sysctl.h>
44
45 #ifdef HAVE_MACH_MACHINE_H
46 #include <mach/machine.h>
47 #endif
48 #ifdef IS_MACOS_X
49 #include <mach-o/arch.h>
50 #endif
51 #endif
52
53 #ifdef __HAIKU__
54 #include <OS.h>
55 #endif
56
57 #ifdef NO_SYSINFO
58 #ifdef HAVE_SYS_SYSTEMINFO_H
59 #undef HAVE_SYS_SYSTEMINFO_H
60 #endif
61 #endif
62
63 EXPORT void setup_arch __PR((void));
64 LOCAL BOOL do_uname __PR((void));
65 LOCAL BOOL do_sysinfo __PR((void));
66 LOCAL BOOL do_sysctl __PR((void));
67 LOCAL BOOL do_haiku __PR((void));
68 LOCAL void do_gethostname __PR((void));
69 LOCAL void do_defs __PR((void));
70 LOCAL void do_archheuristics __PR((void));
71 LOCAL void archcvt __PR((char *));
72 #if defined(HAVE_SYS_SYSTEMINFO_H) || \
73 (defined(HAVE_SYS_SYSCTL_H) && defined(HW_MODEL)) /* See do_sysctl() */
74 LOCAL void unblank __PR((char *));
75 #endif
76
77 /*
78 * External interface to archconf.c. The code tries its best to get the
79 * architecture definitions by calling sysinfo(), uname() or by heuristic.
80 */
81 EXPORT void
setup_arch()82 setup_arch()
83 {
84 if (!do_sysinfo() && /* Call sysinfo(2): preferred */
85 !do_uname()) { /* Call uname(2): still OK */
86 /*
87 * If nothing else helps, at least try to set up $(MAKE_HOST)
88 * and some other macros that may be retrieved from
89 * CPP definitions.
90 */
91 do_gethostname(); /* Try to get host name */
92 do_defs(); /* Evaluate CPP definitions */
93 }
94 do_sysctl();
95 do_haiku();
96
97 do_archheuristics();
98 }
99
100 /*
101 * NeXT Step has sys/utsname but not uname()
102 */
103 #if defined(HAVE_UNAME) || defined(__MINGW32__) || defined(_MSC_VER)
104 /*
105 * This is the interface to the syscall uname(2).
106 * Note that the system call is done directly and not by calling the uname
107 * shell command. If your system returns wrong information with the uname(2)
108 * call, you need to fix it here.
109 */
110 LOCAL BOOL
do_uname()111 do_uname()
112 {
113 struct utsname un;
114
115 if (uname(&un) < 0) {
116 errmsg("Cannot get host arch (uname).\n");
117 return (FALSE);
118 }
119 #ifdef __comment__
120 printf("sysname: %s nodename: %s release: %s version: %s machine: %s\n",
121 un.sysname,
122 un.nodename,
123 un.release,
124 un.version,
125 un.machine);
126 #endif
127 archcvt(un.sysname);
128 archcvt(un.release);
129 archcvt(un.version);
130 archcvt(un.machine);
131
132 define_var("MAKE_OS", un.sysname); /* uname -s */
133 define_var("MAKE_HOST", un.nodename); /* uname -n */
134 define_var("MAKE_OSREL", un.release); /* uname -r */
135 define_var("MAKE_OSVERSION", un.version); /* uname -v */
136 define_var("MAKE_MACH", un.machine); /* uname -m */
137
138 #ifdef HAVE_UTSNAME_PROCESSOR
139 archcvt(un.processor);
140 define_var("MAKE_ARCH", un.processor); /* uname -p */
141 #else
142 #ifdef HAVE_UTSNAME_ARCH /* OpenVMS */
143 archcvt(un.arch);
144 define_var("MAKE_ARCH", un.arch); /* uname -p */
145 #endif
146 #endif
147 #ifdef HAVE_UTSNAME_SYSNAME_HOST
148 archcvt(un.sysname_host);
149 define_var("MAKE_HOST_OS", un.sysname_host); /* uname -Hs */
150 #endif
151 #ifdef HAVE_UTSNAME_RELEASE_HOST
152 archcvt(un.release_host);
153 define_var("MAKE_HOST_OSREL", un.release_host); /* uname -Hr */
154 #endif
155 #ifdef HAVE_UTSNAME_VERSION_HOST
156 archcvt(un.version_host);
157 define_var("MAKE_HOST_OSVERSION", un.version_host); /* uname -Hv */
158 #endif
159
160 return (TRUE);
161 }
162 #else
163
164 /*
165 * Dummy for platforms that don't implement uname(2).
166 */
167 LOCAL BOOL
do_uname()168 do_uname()
169 {
170 return (FALSE);
171 }
172 #endif
173
174 #ifdef HAVE_SYS_SYSTEMINFO_H
175 /*
176 * sysinfo(2) is the preferred way to request architecture information.
177 * Unfortunately, it is only present on SVr4 compliant systems.
178 */
179 LOCAL BOOL
do_sysinfo()180 do_sysinfo()
181 {
182 char nbuf[NAMEMAX];
183 BOOL ret = TRUE;
184
185 #ifdef SI_SYSNAME
186 if (sysinfo(SI_SYSNAME, nbuf, sizeof (nbuf)) < 0) {
187 ret = FALSE;
188 } else {
189 archcvt(nbuf);
190 define_var("MAKE_OS", nbuf); /* uname -s */
191 }
192 #else
193 ret = FALSE;
194 #endif
195
196 #ifdef SI_HOSTNAME
197 if (sysinfo(SI_HOSTNAME, nbuf, sizeof (nbuf)) < 0) {
198 ret = FALSE;
199 } else {
200 define_var("MAKE_HOST", nbuf); /* uname -n */
201 }
202 #else
203 ret = FALSE;
204 #endif
205
206 #ifdef SI_RELEASE
207 if (sysinfo(SI_RELEASE, nbuf, sizeof (nbuf)) < 0) {
208 ret = FALSE;
209 } else {
210 archcvt(nbuf);
211 define_var("MAKE_OSREL", nbuf); /* uname -r */
212 }
213 #else
214 ret = FALSE;
215 #endif
216
217 #ifdef SI_VERSION
218 if (sysinfo(SI_VERSION, nbuf, sizeof (nbuf)) < 0) {
219 ret = FALSE;
220 } else {
221 archcvt(nbuf);
222 define_var("MAKE_OSVERSION", nbuf); /* uname -v */
223 }
224 #else
225 ret = FALSE;
226 #endif
227
228 #ifdef SI_MACHINE
229 if (sysinfo(SI_MACHINE, nbuf, sizeof (nbuf)) < 0) {
230 ret = FALSE;
231 } else {
232 archcvt(nbuf);
233 define_var("MAKE_MACH", nbuf); /* uname -m */
234 }
235 #else
236 ret = FALSE;
237 #endif
238
239 #ifdef SI_ARCHITECTURE
240 if (sysinfo(SI_ARCHITECTURE, nbuf, sizeof (nbuf)) >= 0) {
241 archcvt(nbuf);
242 define_var("MAKE_ARCH", nbuf); /* uname -p */
243 }
244 #endif
245
246 #ifdef SI_PLATFORM
247 if (sysinfo(SI_PLATFORM, nbuf, sizeof (nbuf)) >= 0) {
248 unblank(nbuf);
249 define_var("MAKE_MODEL", nbuf); /* uname -i */
250 }
251 #endif
252
253 #ifdef SI_HW_PROVIDER
254 if (sysinfo(SI_HW_PROVIDER, nbuf, sizeof (nbuf)) >= 0) {
255 unblank(nbuf);
256 #if 0
257 archcvt(nbuf);
258 #endif
259 define_var("MAKE_BRAND", nbuf);
260 }
261 #endif
262
263 #ifdef SI_HW_SERIAL
264 if (sysinfo(SI_HW_SERIAL, nbuf, sizeof (nbuf)) >= 0) {
265 #if 0
266 archcvt(nbuf);
267 #endif
268 define_var("MAKE_HWSERIAL", nbuf);
269 }
270 #endif
271
272 #ifdef SI_SRPC_DOMAIN
273 if (sysinfo(SI_SRPC_DOMAIN, nbuf, sizeof (nbuf)) >= 0) {
274 define_var("MAKE_DOMAIN", nbuf);
275 }
276 #endif
277
278 #ifdef SI_ISALIST
279 if (sysinfo(SI_ISALIST, nbuf, sizeof (nbuf)) >= 0) {
280 define_var("MAKE_ISALIST", nbuf);
281 }
282 #endif
283
284 return (ret);
285 }
286 #else
287
288 /*
289 * Dummy for platforms that don't implement sysinfo(2).
290 */
291 LOCAL BOOL
do_sysinfo()292 do_sysinfo()
293 {
294 return (FALSE);
295 }
296 #endif
297
298 #ifdef HAVE_SYS_SYSCTL_H
299 /*
300 * See #ifdef statement below in unblank()
301 */
302 LOCAL BOOL
do_sysctl()303 do_sysctl()
304 {
305 #if defined(HW_MODEL) || defined(HW_MACHINE_ARCH)
306 char *name;
307 char nbuf[NAMEMAX];
308 size_t len;
309 int mib[2];
310 #endif
311
312 #if defined(HW_MODEL)
313 name = get_var("MAKE_MODEL");
314 if (name == NULL) {
315 mib[0] = CTL_HW;
316 mib[1] = HW_MODEL;
317 len = sizeof (nbuf);
318 if (sysctl(mib, 2, nbuf, &len, 0, 0) >= 0) {
319 unblank(nbuf);
320 define_var("MAKE_MODEL", nbuf);
321 }
322 }
323 #endif /* defined(HW_MODEL) */
324
325 #if defined(HW_MACHINE_ARCH)
326 name = get_var("MAKE_ARCH");
327 if (name == NULL) {
328 mib[0] = CTL_HW;
329 mib[1] = HW_MACHINE_ARCH;
330 len = sizeof (nbuf);
331 if (sysctl(mib, 2, nbuf, &len, 0, 0) >= 0) {
332 archcvt(nbuf);
333 define_var("MAKE_ARCH", nbuf);
334 }
335 #ifdef IS_MACOS_X
336 /*
337 * Mac OS X fails with HW_MACHINE_ARCH
338 */
339 else {
340 cpu_type_t cputype = 0;
341 NXArchInfo const *ai;
342
343 name = NULL;
344 len = sizeof (cputype);
345 if (sysctlbyname("hw.cputype", &cputype, &len,
346 NULL, 0) == 0 &&
347 (ai = NXGetArchInfoFromCpuType(cputype,
348 CPU_SUBTYPE_MULTIPLE)) != NULL) {
349 strlcpy(nbuf, (char *)ai->name, sizeof (nbuf));
350 archcvt(nbuf);
351 name = nbuf;
352 }
353 if (cputype == CPU_TYPE_POWERPC &&
354 name != NULL && strncmp(name, "ppc", 3) == 0) {
355 name = "powerpc";
356 }
357 if (name != NULL)
358 define_var("MAKE_ARCH", name);
359 }
360 #endif /* IS_MACOS_X */
361 }
362 #endif /* defined(HW_MACHINE_ARCH) */
363 return (TRUE);
364 }
365 #else
366 /*
367 * Dummy for platforms that don't implement sysctl().
368 */
369 LOCAL BOOL
do_sysctl()370 do_sysctl()
371 {
372 return (FALSE);
373 }
374 #endif
375
376
377 #ifdef __HAIKU__
378 LOCAL BOOL
do_haiku()379 do_haiku()
380 {
381 char *archname = "unknown";
382 cpu_topology_node_info root;
383 uint32 count = 1;
384 status_t error = get_cpu_topology_info(&root, &count);
385
386 if (error == B_OK && count >= 1) {
387 switch (root.data.root.platform) {
388
389 case B_CPU_x86:
390 archname = "x86";
391 break;
392
393 case B_CPU_x86_64:
394 archname = "x86_64";
395 break;
396
397 case B_CPU_PPC:
398 archname = "ppc";
399 break;
400
401 case B_CPU_PPC_64:
402 archname = "ppc64";
403 break;
404
405 case B_CPU_M68K:
406 archname = "m68k";
407 break;
408
409 case B_CPU_ARM:
410 archname = "arm";
411 break;
412
413 case B_CPU_ARM_64:
414 archname = "arm64";
415 break;
416
417 case B_CPU_ALPHA:
418 archname = "alpha";
419 break;
420
421 case B_CPU_MIPS:
422 archname = "mips";
423 break;
424
425 case B_CPU_SH:
426 archname = "sh";
427 break;
428
429 default:
430 archname = "other";
431 break;
432 }
433 }
434
435 define_var("MAKE_ARCH", archname);
436 return (TRUE);
437 }
438 #else
439 /*
440 * Dummy for platforms that don't implement Haiku get_cpu_topology_info().
441 */
442 LOCAL BOOL
do_haiku()443 do_haiku()
444 {
445 return (FALSE);
446 }
447 #endif
448
449 #ifdef HAVE_GETHOSTNAME
450
451 /*
452 * Don't care for systems that implement a similar functionality in
453 * sysinfo(2) or uname(2). This function is only called if
454 * sysinfo(2) or uname(2) do not exist.
455 */
456 LOCAL void
do_gethostname()457 do_gethostname()
458 {
459 char nbuf[NAMEMAX];
460
461 if (gethostname(nbuf, sizeof (nbuf)) < 0)
462 return;
463
464 define_var("MAKE_HOST", nbuf);
465 }
466 #else
467
468 /*
469 * Dummy for platforms that don't implement gethostname(2).
470 */
471 LOCAL void
do_gethostname()472 do_gethostname()
473 {
474 }
475 #endif
476
477 /*
478 * Try to retrieve some information from CPP definitions.
479 */
480 LOCAL void
do_defs()481 do_defs()
482 {
483 #ifdef IS_MSDOS
484 define_var("MAKE_OS", "msdos");
485 #define FOUND_OS
486 #endif
487 #ifdef IS_TOS
488 define_var("MAKE_OS", "tos");
489 #define FOUND_OS
490 #endif
491 #ifdef IS_MAC
492 define_var("MAKE_OS", "macos");
493 #define FOUND_OS
494 #endif
495 #ifdef __NeXT__
496 define_var("MAKE_OS", "nextstep");
497 #define FOUND_OS
498 define_var("MAKE_OSREL", "3.0");
499 define_var("MAKE_OSVERSION", "1");
500 #ifdef __ARCHITECTURE__
501 define_var("MAKE_MACH", __ARCHITECTURE__);
502 #define FOUND_MACH
503 #endif
504 #endif /* __NeXT__ */
505 #ifdef __MINGW32__
506 define_var("MAKE_OS", "mingw32_nt");
507 #define FOUND_OS
508 #endif
509
510 /*
511 * We need MAKE_OS to allow compilation with the Schily Makefile System
512 */
513 #if !defined(FOUND_OS)
514 define_var("MAKE_OS", "unknown");
515 #define FOUND_OS
516 #endif
517
518 #if !defined(FOUND_MACH) && defined(__mc68010)
519 define_var("MAKE_MACH", "mc68010");
520 #define FOUND_MACH
521 #endif
522 #if !defined(FOUND_MACH) && defined(__mc68000)
523 define_var("MAKE_MACH", "mc68000");
524 #define FOUND_MACH
525 #endif
526 #if !defined(FOUND_MACH) && defined(__i386)
527 define_var("MAKE_MACH", "i386");
528 #define FOUND_MACH
529 #endif
530 #if !defined(FOUND_MACH) && defined(__sparc)
531 define_var("MAKE_MACH", "sparc");
532 #define FOUND_MACH
533 #endif
534 }
535
536 /*
537 * Do some additional heuristic for systems that are already known
538 * but may need some more macro definitions for completion.
539 */
540 LOCAL void
do_archheuristics()541 do_archheuristics()
542 {
543 char *name;
544
545 /*
546 * Try to define global processor architecture
547 */
548 name = get_var("MAKE_ARCH"); /* uname -p is an extension */
549 if (name == NULL) {
550 name = get_var("MAKE_MACH"); /* Check uname -m */
551 if (name != NULL) {
552 if (strstr(name, "sun3"))
553 define_var("MAKE_ARCH", "mc68020");
554 if (strstr(name, "sun4"))
555 define_var("MAKE_ARCH", "sparc");
556 if (strstr(name, "i86pc"))
557 define_var("MAKE_ARCH", "i386");
558 }
559 }
560
561 /*
562 * Try to define global machine architecture
563 */
564 name = get_var("MAKE_MACH");
565 if (name != NULL) {
566 if (strstr(name, "sun3"))
567 define_var("MAKE_M_ARCH", "sun3");
568 if (strstr(name, "sun4"))
569 define_var("MAKE_M_ARCH", "sun4");
570 if (strstr(name, "i86pc"))
571 define_var("MAKE_M_ARCH", "i86pc");
572 }
573
574 name = get_var("MAKE_OS");
575 if (name != NULL) {
576 if (streql(name, "os400")) {
577 /*
578 * OS400 returns serial number in uname -m
579 */
580 if (get_var("MAKE_HWSERIAL") == NULL) {
581 name = get_var("MAKE_MACH");
582 define_var("MAKE_HWSERIAL", name);
583 }
584 define_var("MAKE_MACH", "powerpc");
585 }
586 if (streql(name, "sunos")) {
587 name = get_var("MAKE_OSREL");
588 if (name != NULL && name[0] >= '5')
589 define_var("MAKE_OSDEFS", "-D__SVR4");
590 }
591 }
592 }
593
594 /*
595 * Convert all characters into lower case,
596 * convert '/' into '-',
597 * convert '\\' into '-',
598 * convert ' ' into '-'.
599 */
600 LOCAL void
archcvt(p)601 archcvt(p)
602 register char *p;
603 {
604 register Uchar c;
605
606 while ((c = (Uchar)*p) != '\0') {
607 if (c == '/')
608 *p = '-';
609 if (c == '\\')
610 *p = '-';
611 if (c == ' ')
612 *p = '-';
613 if (isupper(c))
614 *p = tolower(c);
615 p++;
616 }
617 }
618
619 #if defined(HAVE_SYS_SYSTEMINFO_H) || \
620 (defined(HAVE_SYS_SYSCTL_H) && defined(HW_MODEL)) /* See do_sysctl() */
621 /*
622 * Convert all spaces into '-'.
623 */
624 LOCAL void
unblank(p)625 unblank(p)
626 register char *p;
627 {
628 register char c;
629
630 while ((c = *p) != '\0') {
631 if (c == ' ')
632 *p = '-';
633 p++;
634 }
635 }
636 #endif
637