1de572d98SGarrett D'Amore /* 2de572d98SGarrett D'Amore * This file and its contents are supplied under the terms of the 3de572d98SGarrett D'Amore * Common Development and Distribution License ("CDDL"), version 1.0. 4de572d98SGarrett D'Amore * You may only use this file in accordance with the terms of version 5de572d98SGarrett D'Amore * 1.0 of the CDDL. 6de572d98SGarrett D'Amore * 7de572d98SGarrett D'Amore * A full copy of the text of the CDDL should have accompanied this 8de572d98SGarrett D'Amore * source. A copy of the CDDL is also available via the Internet at 9de572d98SGarrett D'Amore * http://www.illumos.org/license/CDDL. 10de572d98SGarrett D'Amore */ 11de572d98SGarrett D'Amore 12de572d98SGarrett D'Amore /* 13de572d98SGarrett D'Amore * Copyright 2015 Garrett D'Amore <garrett@damore.org> 14*1f0c339eSJason King * Copyright 2018 Joyent, Inc. 15de572d98SGarrett D'Amore */ 16de572d98SGarrett D'Amore 17de572d98SGarrett D'Amore /* 18dcdfe824SRobert Mustacchi * This program tests symbol visibility in different compilation environments. 19de572d98SGarrett D'Amore */ 20de572d98SGarrett D'Amore 21de572d98SGarrett D'Amore #include <stdio.h> 22de572d98SGarrett D'Amore #include <stdlib.h> 23de572d98SGarrett D'Amore #include <string.h> 24de572d98SGarrett D'Amore #include <errno.h> 25de572d98SGarrett D'Amore #include <err.h> 26de572d98SGarrett D'Amore #include <unistd.h> 27de572d98SGarrett D'Amore #include <sys/types.h> 28de572d98SGarrett D'Amore #include <sys/stat.h> 29de572d98SGarrett D'Amore #include <note.h> 30*1f0c339eSJason King #include <libcustr.h> 31de572d98SGarrett D'Amore #include <sys/wait.h> 32de572d98SGarrett D'Amore #include "test_common.h" 33de572d98SGarrett D'Amore 34de572d98SGarrett D'Amore char *dname; 35de572d98SGarrett D'Amore char *cfile; 36de572d98SGarrett D'Amore char *ofile; 37de572d98SGarrett D'Amore char *lfile; 38de572d98SGarrett D'Amore char *efile; 39de572d98SGarrett D'Amore 40de572d98SGarrett D'Amore const char *sym = NULL; 41de572d98SGarrett D'Amore 42de572d98SGarrett D'Amore static int good_count = 0; 43de572d98SGarrett D'Amore static int fail_count = 0; 44de572d98SGarrett D'Amore static int full_count = 0; 45de572d98SGarrett D'Amore static int extra_debug = 0; 46de572d98SGarrett D'Amore static char *compilation = "compilation.cfg"; 47de572d98SGarrett D'Amore 48de572d98SGarrett D'Amore #if defined(_LP64) 49de572d98SGarrett D'Amore #define MFLAG "-m64" 50de572d98SGarrett D'Amore #elif defined(_ILP32) 51de572d98SGarrett D'Amore #define MFLAG "-m32" 52de572d98SGarrett D'Amore #endif 53de572d98SGarrett D'Amore 54de572d98SGarrett D'Amore const char *compilers[] = { 55de572d98SGarrett D'Amore "cc", 56de572d98SGarrett D'Amore "gcc", 57de572d98SGarrett D'Amore "/opt/SUNWspro/bin/cc", 58de572d98SGarrett D'Amore "/opt/gcc/4.4.4/bin/gcc", 59de572d98SGarrett D'Amore "/opt/sunstudio12.1/bin/cc", 60de572d98SGarrett D'Amore "/opt/sfw/bin/gcc", 61de572d98SGarrett D'Amore "/usr/local/bin/gcc", 62de572d98SGarrett D'Amore NULL 63de572d98SGarrett D'Amore }; 64de572d98SGarrett D'Amore 65de572d98SGarrett D'Amore char *compiler = NULL; 66de572d98SGarrett D'Amore const char *c89flags = NULL; 67de572d98SGarrett D'Amore const char *c99flags = NULL; 68dcdfe824SRobert Mustacchi const char *c11flags = NULL; 69de572d98SGarrett D'Amore 70de572d98SGarrett D'Amore #define MAXENV 64 /* maximum number of environments (bitmask width) */ 71de572d98SGarrett D'Amore #define MAXHDR 10 /* maximum # headers to require to access symbol */ 72de572d98SGarrett D'Amore #define MAXARG 20 /* maximum # of arguments */ 73de572d98SGarrett D'Amore 74de572d98SGarrett D'Amore #define WS " \t" 75de572d98SGarrett D'Amore 76de572d98SGarrett D'Amore static int next_env = 0; 77de572d98SGarrett D'Amore 78de572d98SGarrett D'Amore struct compile_env { 79de572d98SGarrett D'Amore char *ce_name; 80de572d98SGarrett D'Amore char *ce_lang; 81de572d98SGarrett D'Amore char *ce_defs; 82de572d98SGarrett D'Amore int ce_index; 83de572d98SGarrett D'Amore }; 84de572d98SGarrett D'Amore 85de572d98SGarrett D'Amore static struct compile_env compile_env[MAXENV]; 86de572d98SGarrett D'Amore 87de572d98SGarrett D'Amore struct env_group { 88de572d98SGarrett D'Amore char *eg_name; 89de572d98SGarrett D'Amore uint64_t eg_mask; 90de572d98SGarrett D'Amore struct env_group *eg_next; 91de572d98SGarrett D'Amore }; 92de572d98SGarrett D'Amore 93dcdfe824SRobert Mustacchi typedef enum { 94dcdfe824SRobert Mustacchi SYM_TYPE, 95dcdfe824SRobert Mustacchi SYM_VALUE, 96dcdfe824SRobert Mustacchi SYM_DEFINE, 97dcdfe824SRobert Mustacchi SYM_FUNC 98dcdfe824SRobert Mustacchi } sym_type_t; 99de572d98SGarrett D'Amore 100de572d98SGarrett D'Amore struct sym_test { 101de572d98SGarrett D'Amore char *st_name; 102de572d98SGarrett D'Amore sym_type_t st_type; 103de572d98SGarrett D'Amore char *st_hdrs[MAXHDR]; 104de572d98SGarrett D'Amore char *st_rtype; 105de572d98SGarrett D'Amore char *st_atypes[MAXARG]; 106dcdfe824SRobert Mustacchi char *st_defval; 107de572d98SGarrett D'Amore uint64_t st_test_mask; 108de572d98SGarrett D'Amore uint64_t st_need_mask; 109dcdfe824SRobert Mustacchi const char *st_prog; 110de572d98SGarrett D'Amore struct sym_test *st_next; 111de572d98SGarrett D'Amore }; 112de572d98SGarrett D'Amore 113de572d98SGarrett D'Amore struct env_group *env_groups = NULL; 114de572d98SGarrett D'Amore 115de572d98SGarrett D'Amore struct sym_test *sym_tests = NULL; 116de572d98SGarrett D'Amore struct sym_test **sym_insert = &sym_tests; 117de572d98SGarrett D'Amore 118de572d98SGarrett D'Amore static char * 119de572d98SGarrett D'Amore mystrdup(const char *s) 120de572d98SGarrett D'Amore { 121de572d98SGarrett D'Amore char *r; 122de572d98SGarrett D'Amore if ((r = strdup(s)) == NULL) { 123de572d98SGarrett D'Amore perror("strdup"); 124de572d98SGarrett D'Amore exit(1); 125de572d98SGarrett D'Amore } 126de572d98SGarrett D'Amore return (r); 127de572d98SGarrett D'Amore } 128de572d98SGarrett D'Amore 129de572d98SGarrett D'Amore static void * 130de572d98SGarrett D'Amore myzalloc(size_t sz) 131de572d98SGarrett D'Amore { 132de572d98SGarrett D'Amore void *buf; 133de572d98SGarrett D'Amore if ((buf = calloc(1, sz)) == NULL) { 134de572d98SGarrett D'Amore perror("calloc"); 135de572d98SGarrett D'Amore exit(1); 136de572d98SGarrett D'Amore } 137de572d98SGarrett D'Amore return (buf); 138de572d98SGarrett D'Amore } 139de572d98SGarrett D'Amore 140de572d98SGarrett D'Amore static void 141de572d98SGarrett D'Amore myasprintf(char **buf, const char *fmt, ...) 142de572d98SGarrett D'Amore { 143de572d98SGarrett D'Amore int rv; 144de572d98SGarrett D'Amore va_list va; 145de572d98SGarrett D'Amore va_start(va, fmt); 146de572d98SGarrett D'Amore rv = vasprintf(buf, fmt, va); 147de572d98SGarrett D'Amore va_end(va); 148de572d98SGarrett D'Amore if (rv < 0) { 149de572d98SGarrett D'Amore perror("vasprintf"); 150de572d98SGarrett D'Amore exit(1); 151de572d98SGarrett D'Amore } 152de572d98SGarrett D'Amore } 153de572d98SGarrett D'Amore 154de572d98SGarrett D'Amore static void 155de572d98SGarrett D'Amore append_sym_test(struct sym_test *st) 156de572d98SGarrett D'Amore { 157de572d98SGarrett D'Amore *sym_insert = st; 158de572d98SGarrett D'Amore sym_insert = &st->st_next; 159de572d98SGarrett D'Amore } 160de572d98SGarrett D'Amore 161de572d98SGarrett D'Amore static int 162de572d98SGarrett D'Amore find_env_mask(const char *name, uint64_t *mask) 163de572d98SGarrett D'Amore { 164de572d98SGarrett D'Amore for (int i = 0; i < MAXENV; i++) { 165de572d98SGarrett D'Amore if (compile_env[i].ce_name != NULL && 166de572d98SGarrett D'Amore strcmp(compile_env[i].ce_name, name) == 0) { 167de572d98SGarrett D'Amore *mask |= (1ULL << i); 168de572d98SGarrett D'Amore return (0); 169de572d98SGarrett D'Amore } 170de572d98SGarrett D'Amore } 171de572d98SGarrett D'Amore 172de572d98SGarrett D'Amore for (struct env_group *eg = env_groups; eg != NULL; eg = eg->eg_next) { 173de572d98SGarrett D'Amore if (strcmp(name, eg->eg_name) == 0) { 174de572d98SGarrett D'Amore *mask |= eg->eg_mask; 175de572d98SGarrett D'Amore return (0); 176de572d98SGarrett D'Amore } 177de572d98SGarrett D'Amore } 178de572d98SGarrett D'Amore return (-1); 179de572d98SGarrett D'Amore } 180de572d98SGarrett D'Amore 181de572d98SGarrett D'Amore 182de572d98SGarrett D'Amore static int 183de572d98SGarrett D'Amore expand_env(char *list, uint64_t *mask, char **erritem) 184de572d98SGarrett D'Amore { 185de572d98SGarrett D'Amore char *item; 186de572d98SGarrett D'Amore for (item = strtok(list, WS); item != NULL; item = strtok(NULL, WS)) { 187de572d98SGarrett D'Amore if (find_env_mask(item, mask) < 0) { 188de572d98SGarrett D'Amore if (erritem != NULL) { 189de572d98SGarrett D'Amore *erritem = item; 190de572d98SGarrett D'Amore } 191de572d98SGarrett D'Amore return (-1); 192de572d98SGarrett D'Amore } 193de572d98SGarrett D'Amore } 194de572d98SGarrett D'Amore return (0); 195de572d98SGarrett D'Amore } 196de572d98SGarrett D'Amore 197de572d98SGarrett D'Amore static int 198de572d98SGarrett D'Amore expand_env_list(char *list, uint64_t *test, uint64_t *need, char **erritem) 199de572d98SGarrett D'Amore { 200de572d98SGarrett D'Amore uint64_t mask = 0; 201de572d98SGarrett D'Amore int act; 202de572d98SGarrett D'Amore char *item; 203de572d98SGarrett D'Amore for (item = strtok(list, WS); item != NULL; item = strtok(NULL, WS)) { 204de572d98SGarrett D'Amore switch (item[0]) { 205de572d98SGarrett D'Amore case '+': 206de572d98SGarrett D'Amore act = 1; 207de572d98SGarrett D'Amore item++; 208de572d98SGarrett D'Amore break; 209de572d98SGarrett D'Amore case '-': 210de572d98SGarrett D'Amore act = 0; 211de572d98SGarrett D'Amore item++; 212de572d98SGarrett D'Amore break; 213de572d98SGarrett D'Amore default: 214de572d98SGarrett D'Amore act = 1; 215de572d98SGarrett D'Amore break; 216de572d98SGarrett D'Amore } 217de572d98SGarrett D'Amore 218de572d98SGarrett D'Amore mask = 0; 219de572d98SGarrett D'Amore if (find_env_mask(item, &mask) < 0) { 220de572d98SGarrett D'Amore if (erritem != NULL) { 221de572d98SGarrett D'Amore *erritem = item; 222de572d98SGarrett D'Amore } 223de572d98SGarrett D'Amore return (-1); 224de572d98SGarrett D'Amore } 225de572d98SGarrett D'Amore *test |= mask; 226de572d98SGarrett D'Amore if (act) { 227de572d98SGarrett D'Amore *need |= mask; 228de572d98SGarrett D'Amore } else { 229de572d98SGarrett D'Amore *need &= ~(mask); 230de572d98SGarrett D'Amore } 231de572d98SGarrett D'Amore } 232de572d98SGarrett D'Amore return (0); 233de572d98SGarrett D'Amore } 234de572d98SGarrett D'Amore 235de572d98SGarrett D'Amore static int 236de572d98SGarrett D'Amore do_env(char **fields, int nfields, char **err) 237de572d98SGarrett D'Amore { 238de572d98SGarrett D'Amore char *name; 239de572d98SGarrett D'Amore char *lang; 240de572d98SGarrett D'Amore char *defs; 241de572d98SGarrett D'Amore 242de572d98SGarrett D'Amore if (nfields != 3) { 243de572d98SGarrett D'Amore myasprintf(err, "number of fields (%d) != 3", nfields); 244de572d98SGarrett D'Amore return (-1); 245de572d98SGarrett D'Amore } 246de572d98SGarrett D'Amore 247de572d98SGarrett D'Amore if (next_env >= MAXENV) { 248de572d98SGarrett D'Amore myasprintf(err, "too many environments"); 249de572d98SGarrett D'Amore return (-1); 250de572d98SGarrett D'Amore } 251de572d98SGarrett D'Amore 252de572d98SGarrett D'Amore name = fields[0]; 253de572d98SGarrett D'Amore lang = fields[1]; 254de572d98SGarrett D'Amore defs = fields[2]; 255de572d98SGarrett D'Amore 256de572d98SGarrett D'Amore compile_env[next_env].ce_name = mystrdup(name); 257de572d98SGarrett D'Amore compile_env[next_env].ce_lang = mystrdup(lang); 258de572d98SGarrett D'Amore compile_env[next_env].ce_defs = mystrdup(defs); 259de572d98SGarrett D'Amore compile_env[next_env].ce_index = next_env; 260de572d98SGarrett D'Amore next_env++; 261de572d98SGarrett D'Amore return (0); 262de572d98SGarrett D'Amore } 263de572d98SGarrett D'Amore 264de572d98SGarrett D'Amore static int 265de572d98SGarrett D'Amore do_env_group(char **fields, int nfields, char **err) 266de572d98SGarrett D'Amore { 267de572d98SGarrett D'Amore char *name; 268de572d98SGarrett D'Amore char *list; 269de572d98SGarrett D'Amore struct env_group *eg; 270de572d98SGarrett D'Amore uint64_t mask; 271de572d98SGarrett D'Amore char *item; 272de572d98SGarrett D'Amore 273de572d98SGarrett D'Amore if (nfields != 2) { 274de572d98SGarrett D'Amore myasprintf(err, "number of fields (%d) != 2", nfields); 275de572d98SGarrett D'Amore return (-1); 276de572d98SGarrett D'Amore } 277de572d98SGarrett D'Amore 278de572d98SGarrett D'Amore name = fields[0]; 279de572d98SGarrett D'Amore list = fields[1]; 280de572d98SGarrett D'Amore mask = 0; 281de572d98SGarrett D'Amore 282de572d98SGarrett D'Amore if (expand_env(list, &mask, &item) < 0) { 283de572d98SGarrett D'Amore myasprintf(err, "reference to undefined env %s", item); 284de572d98SGarrett D'Amore return (-1); 285de572d98SGarrett D'Amore } 286de572d98SGarrett D'Amore 287de572d98SGarrett D'Amore eg = myzalloc(sizeof (*eg)); 288de572d98SGarrett D'Amore eg->eg_name = mystrdup(name); 289de572d98SGarrett D'Amore eg->eg_mask = mask; 290de572d98SGarrett D'Amore eg->eg_next = env_groups; 291de572d98SGarrett D'Amore env_groups = eg; 292de572d98SGarrett D'Amore return (0); 293de572d98SGarrett D'Amore } 294de572d98SGarrett D'Amore 295dcdfe824SRobert Mustacchi static custr_t *st_custr; 296de572d98SGarrett D'Amore 297de572d98SGarrett D'Amore static void 298de572d98SGarrett D'Amore addprogch(char c) 299de572d98SGarrett D'Amore { 300dcdfe824SRobert Mustacchi if (custr_appendc(st_custr, c) == -1) { 301dcdfe824SRobert Mustacchi perror("custr_appendc"); 302de572d98SGarrett D'Amore exit(1); 303de572d98SGarrett D'Amore } 304de572d98SGarrett D'Amore } 305de572d98SGarrett D'Amore 306de572d98SGarrett D'Amore static void 307de572d98SGarrett D'Amore addprogstr(char *s) 308de572d98SGarrett D'Amore { 309dcdfe824SRobert Mustacchi if (custr_append(st_custr, s) == -1) { 310dcdfe824SRobert Mustacchi perror("custr_append"); 311dcdfe824SRobert Mustacchi exit(1); 312de572d98SGarrett D'Amore } 313de572d98SGarrett D'Amore } 314de572d98SGarrett D'Amore 315de572d98SGarrett D'Amore static void 316de572d98SGarrett D'Amore addprogfmt(const char *fmt, ...) 317de572d98SGarrett D'Amore { 318de572d98SGarrett D'Amore va_list va; 319de572d98SGarrett D'Amore va_start(va, fmt); 320dcdfe824SRobert Mustacchi if (custr_append_vprintf(st_custr, fmt, va) == -1) { 321dcdfe824SRobert Mustacchi perror("custr_append_vprintf"); 322de572d98SGarrett D'Amore exit(1); 323de572d98SGarrett D'Amore } 324de572d98SGarrett D'Amore va_end(va); 325de572d98SGarrett D'Amore } 326de572d98SGarrett D'Amore 327de572d98SGarrett D'Amore static void 328de572d98SGarrett D'Amore mkprog(struct sym_test *st) 329de572d98SGarrett D'Amore { 330dcdfe824SRobert Mustacchi char *s = NULL; 331de572d98SGarrett D'Amore 332dcdfe824SRobert Mustacchi custr_reset(st_custr); 333de572d98SGarrett D'Amore 334de572d98SGarrett D'Amore for (int i = 0; i < MAXHDR && st->st_hdrs[i] != NULL; i++) { 335de572d98SGarrett D'Amore addprogfmt("#include <%s>\n", st->st_hdrs[i]); 336de572d98SGarrett D'Amore } 337de572d98SGarrett D'Amore 338dcdfe824SRobert Mustacchi if (st->st_rtype != NULL) { 339de572d98SGarrett D'Amore for (s = st->st_rtype; *s; s++) { 340de572d98SGarrett D'Amore addprogch(*s); 341de572d98SGarrett D'Amore if (*s == '(') { 342de572d98SGarrett D'Amore s++; 343de572d98SGarrett D'Amore addprogch(*s); 344de572d98SGarrett D'Amore s++; 345de572d98SGarrett D'Amore break; 346de572d98SGarrett D'Amore } 347de572d98SGarrett D'Amore } 348de572d98SGarrett D'Amore addprogch(' '); 349dcdfe824SRobert Mustacchi } 350de572d98SGarrett D'Amore 351de572d98SGarrett D'Amore /* for function pointers, s is closing suffix, otherwise empty */ 352de572d98SGarrett D'Amore 353de572d98SGarrett D'Amore switch (st->st_type) { 354de572d98SGarrett D'Amore case SYM_TYPE: 355de572d98SGarrett D'Amore addprogstr("test_type;"); 356de572d98SGarrett D'Amore break; 357de572d98SGarrett D'Amore 358de572d98SGarrett D'Amore case SYM_VALUE: 359de572d98SGarrett D'Amore addprogfmt("test_value%s;\n", s); /* s usually empty */ 360de572d98SGarrett D'Amore addprogstr("void\ntest_func(void)\n{\n"); 361de572d98SGarrett D'Amore addprogfmt("\ttest_value = %s;\n}", st->st_name); 362de572d98SGarrett D'Amore break; 363de572d98SGarrett D'Amore 364dcdfe824SRobert Mustacchi case SYM_DEFINE: 365dcdfe824SRobert Mustacchi addprogfmt("#if !defined(%s)", st->st_name); 366dcdfe824SRobert Mustacchi if (st->st_defval != NULL) 367dcdfe824SRobert Mustacchi addprogfmt("|| %s != %s", st->st_name, st->st_defval); 368dcdfe824SRobert Mustacchi addprogfmt("\n#error %s is not defined or has the wrong value", 369dcdfe824SRobert Mustacchi st->st_name); 370dcdfe824SRobert Mustacchi addprogfmt("\n#endif\n"); 371dcdfe824SRobert Mustacchi break; 372dcdfe824SRobert Mustacchi 373de572d98SGarrett D'Amore case SYM_FUNC: 374de572d98SGarrett D'Amore addprogstr("\ntest_func("); 375de572d98SGarrett D'Amore for (int i = 0; st->st_atypes[i] != NULL && i < MAXARG; i++) { 376de572d98SGarrett D'Amore int didname = 0; 377de572d98SGarrett D'Amore if (i > 0) { 378de572d98SGarrett D'Amore addprogstr(", "); 379de572d98SGarrett D'Amore } 380de572d98SGarrett D'Amore if (strcmp(st->st_atypes[i], "void") == 0) { 381de572d98SGarrett D'Amore didname = 1; 382de572d98SGarrett D'Amore } 383de572d98SGarrett D'Amore if (strcmp(st->st_atypes[i], "") == 0) { 384de572d98SGarrett D'Amore didname = 1; 385de572d98SGarrett D'Amore addprogstr("void"); 386de572d98SGarrett D'Amore } 387de572d98SGarrett D'Amore 388de572d98SGarrett D'Amore /* print the argument list */ 389de572d98SGarrett D'Amore for (char *a = st->st_atypes[i]; *a; a++) { 390de572d98SGarrett D'Amore if (*a == '(' && a[1] == '*' && !didname) { 391de572d98SGarrett D'Amore addprogfmt("(*a%d", i); 392de572d98SGarrett D'Amore didname = 1; 393de572d98SGarrett D'Amore a++; 394de572d98SGarrett D'Amore } else if (*a == '[' && !didname) { 395de572d98SGarrett D'Amore addprogfmt("a%d[", i); 396de572d98SGarrett D'Amore didname = 1; 397de572d98SGarrett D'Amore } else { 398de572d98SGarrett D'Amore addprogch(*a); 399de572d98SGarrett D'Amore } 400de572d98SGarrett D'Amore } 401de572d98SGarrett D'Amore if (!didname) { 402de572d98SGarrett D'Amore addprogfmt(" a%d", i); 403de572d98SGarrett D'Amore } 404de572d98SGarrett D'Amore } 405de572d98SGarrett D'Amore 406de572d98SGarrett D'Amore if (st->st_atypes[0] == NULL) { 407de572d98SGarrett D'Amore addprogstr("void"); 408de572d98SGarrett D'Amore } 409de572d98SGarrett D'Amore 410de572d98SGarrett D'Amore /* 411de572d98SGarrett D'Amore * Close argument list, and closing ")" for func ptrs. 412de572d98SGarrett D'Amore * Note that for non-function pointers, s will be empty 413de572d98SGarrett D'Amore * below, otherwise it points to the trailing argument 414de572d98SGarrett D'Amore * list. 415de572d98SGarrett D'Amore */ 416de572d98SGarrett D'Amore addprogfmt(")%s\n{\n\t", s); 417de572d98SGarrett D'Amore 418de572d98SGarrett D'Amore if (strcmp(st->st_rtype, "") != 0 && 419de572d98SGarrett D'Amore strcmp(st->st_rtype, "void") != 0) { 420de572d98SGarrett D'Amore addprogstr("return "); 421de572d98SGarrett D'Amore } 422de572d98SGarrett D'Amore 423de572d98SGarrett D'Amore /* add the function call */ 424de572d98SGarrett D'Amore addprogfmt("%s(", st->st_name); 425de572d98SGarrett D'Amore for (int i = 0; st->st_atypes[i] != NULL && i < MAXARG; i++) { 426de572d98SGarrett D'Amore if (strcmp(st->st_atypes[i], "") != 0 && 427de572d98SGarrett D'Amore strcmp(st->st_atypes[i], "void") != 0) { 428de572d98SGarrett D'Amore addprogfmt("%sa%d", i > 0 ? ", " : "", i); 429de572d98SGarrett D'Amore } 430de572d98SGarrett D'Amore } 431de572d98SGarrett D'Amore 432de572d98SGarrett D'Amore addprogstr(");\n}"); 433de572d98SGarrett D'Amore break; 434de572d98SGarrett D'Amore } 435de572d98SGarrett D'Amore 436de572d98SGarrett D'Amore addprogch('\n'); 437de572d98SGarrett D'Amore 438dcdfe824SRobert Mustacchi st->st_prog = custr_cstr(st_custr); 439de572d98SGarrett D'Amore } 440de572d98SGarrett D'Amore 441de572d98SGarrett D'Amore static int 442de572d98SGarrett D'Amore add_envs(struct sym_test *st, char *envs, char **err) 443de572d98SGarrett D'Amore { 444de572d98SGarrett D'Amore char *item; 445de572d98SGarrett D'Amore if (expand_env_list(envs, &st->st_test_mask, &st->st_need_mask, 446de572d98SGarrett D'Amore &item) < 0) { 447de572d98SGarrett D'Amore myasprintf(err, "bad env action %s", item); 448de572d98SGarrett D'Amore return (-1); 449de572d98SGarrett D'Amore } 450de572d98SGarrett D'Amore return (0); 451de572d98SGarrett D'Amore } 452de572d98SGarrett D'Amore 453de572d98SGarrett D'Amore static int 454de572d98SGarrett D'Amore add_headers(struct sym_test *st, char *hdrs, char **err) 455de572d98SGarrett D'Amore { 456de572d98SGarrett D'Amore int i = 0; 457de572d98SGarrett D'Amore 458de572d98SGarrett D'Amore for (char *h = strsep(&hdrs, ";"); h != NULL; h = strsep(&hdrs, ";")) { 459de572d98SGarrett D'Amore if (i >= MAXHDR) { 460de572d98SGarrett D'Amore myasprintf(err, "too many headers"); 461de572d98SGarrett D'Amore return (-1); 462de572d98SGarrett D'Amore } 463de572d98SGarrett D'Amore test_trim(&h); 464de572d98SGarrett D'Amore st->st_hdrs[i++] = mystrdup(h); 465de572d98SGarrett D'Amore } 466de572d98SGarrett D'Amore 467de572d98SGarrett D'Amore return (0); 468de572d98SGarrett D'Amore } 469de572d98SGarrett D'Amore 470de572d98SGarrett D'Amore static int 471de572d98SGarrett D'Amore add_arg_types(struct sym_test *st, char *atype, char **err) 472de572d98SGarrett D'Amore { 473de572d98SGarrett D'Amore int i = 0; 474de572d98SGarrett D'Amore char *a; 475de572d98SGarrett D'Amore for (a = strsep(&atype, ";"); a != NULL; a = strsep(&atype, ";")) { 476de572d98SGarrett D'Amore if (i >= MAXARG) { 477de572d98SGarrett D'Amore myasprintf(err, "too many arguments"); 478de572d98SGarrett D'Amore return (-1); 479de572d98SGarrett D'Amore } 480de572d98SGarrett D'Amore test_trim(&a); 481de572d98SGarrett D'Amore st->st_atypes[i++] = mystrdup(a); 482de572d98SGarrett D'Amore } 483de572d98SGarrett D'Amore 484de572d98SGarrett D'Amore return (0); 485de572d98SGarrett D'Amore } 486de572d98SGarrett D'Amore 487de572d98SGarrett D'Amore static int 488de572d98SGarrett D'Amore do_type(char **fields, int nfields, char **err) 489de572d98SGarrett D'Amore { 490de572d98SGarrett D'Amore char *decl; 491de572d98SGarrett D'Amore char *hdrs; 492de572d98SGarrett D'Amore char *envs; 493de572d98SGarrett D'Amore struct sym_test *st; 494de572d98SGarrett D'Amore 495de572d98SGarrett D'Amore if (nfields != 3) { 496de572d98SGarrett D'Amore myasprintf(err, "number of fields (%d) != 3", nfields); 497de572d98SGarrett D'Amore return (-1); 498de572d98SGarrett D'Amore } 499de572d98SGarrett D'Amore decl = fields[0]; 500de572d98SGarrett D'Amore hdrs = fields[1]; 501de572d98SGarrett D'Amore envs = fields[2]; 502de572d98SGarrett D'Amore 503de572d98SGarrett D'Amore st = myzalloc(sizeof (*st)); 504de572d98SGarrett D'Amore st->st_type = SYM_TYPE; 505de572d98SGarrett D'Amore st->st_name = mystrdup(decl); 506de572d98SGarrett D'Amore st->st_rtype = mystrdup(decl); 507de572d98SGarrett D'Amore 508de572d98SGarrett D'Amore if ((add_envs(st, envs, err) < 0) || 509de572d98SGarrett D'Amore (add_headers(st, hdrs, err) < 0)) { 510de572d98SGarrett D'Amore return (-1); 511de572d98SGarrett D'Amore } 512de572d98SGarrett D'Amore append_sym_test(st); 513de572d98SGarrett D'Amore 514de572d98SGarrett D'Amore return (0); 515de572d98SGarrett D'Amore } 516de572d98SGarrett D'Amore 517de572d98SGarrett D'Amore static int 518de572d98SGarrett D'Amore do_value(char **fields, int nfields, char **err) 519de572d98SGarrett D'Amore { 520de572d98SGarrett D'Amore char *name; 521de572d98SGarrett D'Amore char *type; 522de572d98SGarrett D'Amore char *hdrs; 523de572d98SGarrett D'Amore char *envs; 524de572d98SGarrett D'Amore struct sym_test *st; 525de572d98SGarrett D'Amore 526de572d98SGarrett D'Amore if (nfields != 4) { 527de572d98SGarrett D'Amore myasprintf(err, "number of fields (%d) != 4", nfields); 528de572d98SGarrett D'Amore return (-1); 529de572d98SGarrett D'Amore } 530de572d98SGarrett D'Amore name = fields[0]; 531de572d98SGarrett D'Amore type = fields[1]; 532de572d98SGarrett D'Amore hdrs = fields[2]; 533de572d98SGarrett D'Amore envs = fields[3]; 534de572d98SGarrett D'Amore 535de572d98SGarrett D'Amore st = myzalloc(sizeof (*st)); 536de572d98SGarrett D'Amore st->st_type = SYM_VALUE; 537de572d98SGarrett D'Amore st->st_name = mystrdup(name); 538de572d98SGarrett D'Amore st->st_rtype = mystrdup(type); 539de572d98SGarrett D'Amore 540de572d98SGarrett D'Amore if ((add_envs(st, envs, err) < 0) || 541de572d98SGarrett D'Amore (add_headers(st, hdrs, err) < 0)) { 542de572d98SGarrett D'Amore return (-1); 543de572d98SGarrett D'Amore } 544de572d98SGarrett D'Amore append_sym_test(st); 545de572d98SGarrett D'Amore 546de572d98SGarrett D'Amore return (0); 547de572d98SGarrett D'Amore } 548de572d98SGarrett D'Amore 549de572d98SGarrett D'Amore static int 550dcdfe824SRobert Mustacchi do_define(char **fields, int nfields, char **err) 551dcdfe824SRobert Mustacchi { 552dcdfe824SRobert Mustacchi char *name, *value, *hdrs, *envs; 553dcdfe824SRobert Mustacchi struct sym_test *st; 554dcdfe824SRobert Mustacchi 555dcdfe824SRobert Mustacchi if (nfields != 4) { 556dcdfe824SRobert Mustacchi myasprintf(err, "number of fields (%d) != 4", nfields); 557dcdfe824SRobert Mustacchi return (-1); 558dcdfe824SRobert Mustacchi } 559dcdfe824SRobert Mustacchi 560dcdfe824SRobert Mustacchi name = fields[0]; 561dcdfe824SRobert Mustacchi value = fields[1]; 562dcdfe824SRobert Mustacchi hdrs = fields[2]; 563dcdfe824SRobert Mustacchi envs = fields[3]; 564dcdfe824SRobert Mustacchi 565dcdfe824SRobert Mustacchi st = myzalloc(sizeof (*st)); 566dcdfe824SRobert Mustacchi st->st_type = SYM_DEFINE; 567dcdfe824SRobert Mustacchi st->st_name = mystrdup(name); 568dcdfe824SRobert Mustacchi 569dcdfe824SRobert Mustacchi /* 570dcdfe824SRobert Mustacchi * A value to compare against is optional. trim will leave it as a null 571dcdfe824SRobert Mustacchi * pointer if there's nothing there. 572dcdfe824SRobert Mustacchi */ 573dcdfe824SRobert Mustacchi test_trim(&value); 574dcdfe824SRobert Mustacchi if (*value != '\0') 575dcdfe824SRobert Mustacchi st->st_defval = mystrdup(value); 576dcdfe824SRobert Mustacchi 577dcdfe824SRobert Mustacchi if ((add_envs(st, envs, err) < 0) || 578dcdfe824SRobert Mustacchi (add_headers(st, hdrs, err) < 0)) { 579dcdfe824SRobert Mustacchi return (-1); 580dcdfe824SRobert Mustacchi } 581dcdfe824SRobert Mustacchi 582dcdfe824SRobert Mustacchi append_sym_test(st); 583dcdfe824SRobert Mustacchi 584dcdfe824SRobert Mustacchi return (0); 585dcdfe824SRobert Mustacchi } 586dcdfe824SRobert Mustacchi 587dcdfe824SRobert Mustacchi static int 588de572d98SGarrett D'Amore do_func(char **fields, int nfields, char **err) 589de572d98SGarrett D'Amore { 590de572d98SGarrett D'Amore char *name; 591de572d98SGarrett D'Amore char *rtype; 592de572d98SGarrett D'Amore char *atype; 593de572d98SGarrett D'Amore char *hdrs; 594de572d98SGarrett D'Amore char *envs; 595de572d98SGarrett D'Amore struct sym_test *st; 596de572d98SGarrett D'Amore 597de572d98SGarrett D'Amore if (nfields != 5) { 598de572d98SGarrett D'Amore myasprintf(err, "number of fields (%d) != 5", nfields); 599de572d98SGarrett D'Amore return (-1); 600de572d98SGarrett D'Amore } 601de572d98SGarrett D'Amore name = fields[0]; 602de572d98SGarrett D'Amore rtype = fields[1]; 603de572d98SGarrett D'Amore atype = fields[2]; 604de572d98SGarrett D'Amore hdrs = fields[3]; 605de572d98SGarrett D'Amore envs = fields[4]; 606de572d98SGarrett D'Amore 607de572d98SGarrett D'Amore st = myzalloc(sizeof (*st)); 608de572d98SGarrett D'Amore st->st_type = SYM_FUNC; 609de572d98SGarrett D'Amore st->st_name = mystrdup(name); 610de572d98SGarrett D'Amore st->st_rtype = mystrdup(rtype); 611de572d98SGarrett D'Amore 612de572d98SGarrett D'Amore if ((add_envs(st, envs, err) < 0) || 613de572d98SGarrett D'Amore (add_headers(st, hdrs, err) < 0) || 614de572d98SGarrett D'Amore (add_arg_types(st, atype, err) < 0)) { 615de572d98SGarrett D'Amore return (-1); 616de572d98SGarrett D'Amore } 617de572d98SGarrett D'Amore append_sym_test(st); 618de572d98SGarrett D'Amore 619de572d98SGarrett D'Amore return (0); 620de572d98SGarrett D'Amore } 621de572d98SGarrett D'Amore 622de572d98SGarrett D'Amore struct sym_test * 623de572d98SGarrett D'Amore next_sym_test(struct sym_test *st) 624de572d98SGarrett D'Amore { 625de572d98SGarrett D'Amore return (st == NULL ? sym_tests : st->st_next); 626de572d98SGarrett D'Amore } 627de572d98SGarrett D'Amore 628de572d98SGarrett D'Amore const char * 629de572d98SGarrett D'Amore sym_test_prog(struct sym_test *st) 630de572d98SGarrett D'Amore { 631de572d98SGarrett D'Amore if (st->st_prog == NULL) { 632de572d98SGarrett D'Amore mkprog(st); 633de572d98SGarrett D'Amore } 634de572d98SGarrett D'Amore return (st->st_prog); 635de572d98SGarrett D'Amore } 636de572d98SGarrett D'Amore 637de572d98SGarrett D'Amore const char * 638de572d98SGarrett D'Amore sym_test_name(struct sym_test *st) 639de572d98SGarrett D'Amore { 640de572d98SGarrett D'Amore return (st->st_name); 641de572d98SGarrett D'Amore } 642de572d98SGarrett D'Amore 643de572d98SGarrett D'Amore /* 644de572d98SGarrett D'Amore * Iterate through tests. Pass in NULL for cenv to begin the iteration. For 645de572d98SGarrett D'Amore * subsequent iterations, use the return value from the previous iteration. 646de572d98SGarrett D'Amore * Returns NULL when there are no more environments. 647de572d98SGarrett D'Amore */ 648de572d98SGarrett D'Amore struct compile_env * 649de572d98SGarrett D'Amore sym_test_env(struct sym_test *st, struct compile_env *cenv, int *need) 650de572d98SGarrett D'Amore { 651de572d98SGarrett D'Amore int i = cenv ? cenv->ce_index + 1: 0; 652de572d98SGarrett D'Amore uint64_t b = 1ULL << i; 653de572d98SGarrett D'Amore 654de572d98SGarrett D'Amore while ((i < MAXENV) && (b != 0)) { 655de572d98SGarrett D'Amore cenv = &compile_env[i]; 656de572d98SGarrett D'Amore if (b & st->st_test_mask) { 657de572d98SGarrett D'Amore *need = (st->st_need_mask & b) ? 1 : 0; 658de572d98SGarrett D'Amore return (cenv); 659de572d98SGarrett D'Amore } 660de572d98SGarrett D'Amore b <<= 1; 661de572d98SGarrett D'Amore i++; 662de572d98SGarrett D'Amore } 663de572d98SGarrett D'Amore return (NULL); 664de572d98SGarrett D'Amore } 665de572d98SGarrett D'Amore 666de572d98SGarrett D'Amore const char * 667de572d98SGarrett D'Amore env_name(struct compile_env *cenv) 668de572d98SGarrett D'Amore { 669de572d98SGarrett D'Amore return (cenv->ce_name); 670de572d98SGarrett D'Amore } 671de572d98SGarrett D'Amore 672de572d98SGarrett D'Amore const char * 673de572d98SGarrett D'Amore env_lang(struct compile_env *cenv) 674de572d98SGarrett D'Amore { 675de572d98SGarrett D'Amore return (cenv->ce_lang); 676de572d98SGarrett D'Amore } 677de572d98SGarrett D'Amore 678de572d98SGarrett D'Amore const char * 679de572d98SGarrett D'Amore env_defs(struct compile_env *cenv) 680de572d98SGarrett D'Amore { 681de572d98SGarrett D'Amore return (cenv->ce_defs); 682de572d98SGarrett D'Amore } 683de572d98SGarrett D'Amore 684de572d98SGarrett D'Amore static void 685de572d98SGarrett D'Amore show_file(test_t t, const char *path) 686de572d98SGarrett D'Amore { 687de572d98SGarrett D'Amore FILE *f; 688de572d98SGarrett D'Amore char *buf = NULL; 689de572d98SGarrett D'Amore size_t cap = 0; 690de572d98SGarrett D'Amore int line = 1; 691de572d98SGarrett D'Amore 692de572d98SGarrett D'Amore f = fopen(path, "r"); 693de572d98SGarrett D'Amore if (f == NULL) { 694de572d98SGarrett D'Amore test_debugf(t, "fopen(%s): %s", path, strerror(errno)); 695de572d98SGarrett D'Amore return; 696de572d98SGarrett D'Amore } 697de572d98SGarrett D'Amore 698de572d98SGarrett D'Amore test_debugf(t, "----->> begin (%s) <<------", path); 699de572d98SGarrett D'Amore while (getline(&buf, &cap, f) >= 0) { 700de572d98SGarrett D'Amore (void) strtok(buf, "\r\n"); 701de572d98SGarrett D'Amore test_debugf(t, "%d: %s", line, buf); 702de572d98SGarrett D'Amore line++; 703de572d98SGarrett D'Amore } 704de572d98SGarrett D'Amore test_debugf(t, "----->> end (%s) <<------", path); 705de572d98SGarrett D'Amore (void) fclose(f); 706de572d98SGarrett D'Amore } 707de572d98SGarrett D'Amore 708de572d98SGarrett D'Amore static void 709de572d98SGarrett D'Amore cleanup(void) 710de572d98SGarrett D'Amore { 711de572d98SGarrett D'Amore if (ofile != NULL) { 712de572d98SGarrett D'Amore (void) unlink(ofile); 713de572d98SGarrett D'Amore free(ofile); 714de572d98SGarrett D'Amore ofile = NULL; 715de572d98SGarrett D'Amore } 716de572d98SGarrett D'Amore if (lfile != NULL) { 717de572d98SGarrett D'Amore (void) unlink(lfile); 718de572d98SGarrett D'Amore free(lfile); 719de572d98SGarrett D'Amore lfile = NULL; 720de572d98SGarrett D'Amore } 721de572d98SGarrett D'Amore if (cfile != NULL) { 722de572d98SGarrett D'Amore (void) unlink(cfile); 723de572d98SGarrett D'Amore free(cfile); 724de572d98SGarrett D'Amore cfile = NULL; 725de572d98SGarrett D'Amore } 726de572d98SGarrett D'Amore if (efile != NULL) { 727de572d98SGarrett D'Amore (void) unlink(efile); 728de572d98SGarrett D'Amore free(efile); 729de572d98SGarrett D'Amore efile = NULL; 730de572d98SGarrett D'Amore } 731de572d98SGarrett D'Amore if (dname) { 732de572d98SGarrett D'Amore (void) rmdir(dname); 733de572d98SGarrett D'Amore free(dname); 734de572d98SGarrett D'Amore dname = NULL; 735de572d98SGarrett D'Amore } 736de572d98SGarrett D'Amore } 737de572d98SGarrett D'Amore 738de572d98SGarrett D'Amore static int 739de572d98SGarrett D'Amore mkworkdir(void) 740de572d98SGarrett D'Amore { 741de572d98SGarrett D'Amore char b[32]; 742de572d98SGarrett D'Amore char *d; 743de572d98SGarrett D'Amore 744de572d98SGarrett D'Amore cleanup(); 745de572d98SGarrett D'Amore 746de572d98SGarrett D'Amore (void) strlcpy(b, "/tmp/symbols_testXXXXXX", sizeof (b)); 747de572d98SGarrett D'Amore if ((d = mkdtemp(b)) == NULL) { 748de572d98SGarrett D'Amore perror("mkdtemp"); 749de572d98SGarrett D'Amore return (-1); 750de572d98SGarrett D'Amore } 751de572d98SGarrett D'Amore dname = mystrdup(d); 752de572d98SGarrett D'Amore myasprintf(&cfile, "%s/compile_test.c", d); 753de572d98SGarrett D'Amore myasprintf(&ofile, "%s/compile_test.o", d); 754de572d98SGarrett D'Amore myasprintf(&lfile, "%s/compile_test.log", d); 755de572d98SGarrett D'Amore myasprintf(&efile, "%s/compile_test.exe", d); 756de572d98SGarrett D'Amore return (0); 757de572d98SGarrett D'Amore } 758de572d98SGarrett D'Amore 759de572d98SGarrett D'Amore void 760de572d98SGarrett D'Amore find_compiler(void) 761de572d98SGarrett D'Amore { 762de572d98SGarrett D'Amore test_t t; 763de572d98SGarrett D'Amore int i; 764de572d98SGarrett D'Amore FILE *cf; 765de572d98SGarrett D'Amore 766de572d98SGarrett D'Amore t = test_start("finding compiler"); 767de572d98SGarrett D'Amore 768de572d98SGarrett D'Amore if ((cf = fopen(cfile, "w+")) == NULL) { 769de572d98SGarrett D'Amore test_failed(t, "Unable to open %s for write: %s", cfile, 770de572d98SGarrett D'Amore strerror(errno)); 771de572d98SGarrett D'Amore return; 772de572d98SGarrett D'Amore } 773de572d98SGarrett D'Amore (void) fprintf(cf, "#include <stdio.h>\n"); 774de572d98SGarrett D'Amore (void) fprintf(cf, "int main(int argc, char **argv) {\n"); 775de572d98SGarrett D'Amore (void) fprintf(cf, "#if defined(__SUNPRO_C)\n"); 776de572d98SGarrett D'Amore (void) fprintf(cf, "exit(51);\n"); 777de572d98SGarrett D'Amore (void) fprintf(cf, "#elif defined(__GNUC__)\n"); 778de572d98SGarrett D'Amore (void) fprintf(cf, "exit(52);\n"); 779de572d98SGarrett D'Amore (void) fprintf(cf, "#else\n"); 780de572d98SGarrett D'Amore (void) fprintf(cf, "exit(99)\n"); 781de572d98SGarrett D'Amore (void) fprintf(cf, "#endif\n}\n"); 782de572d98SGarrett D'Amore (void) fclose(cf); 783de572d98SGarrett D'Amore 784de572d98SGarrett D'Amore for (i = 0; compilers[i] != NULL; i++) { 785de572d98SGarrett D'Amore char cmd[256]; 786de572d98SGarrett D'Amore int rv; 787de572d98SGarrett D'Amore 788de572d98SGarrett D'Amore (void) snprintf(cmd, sizeof (cmd), 789de572d98SGarrett D'Amore "%s %s %s -o %s >/dev/null 2>&1", 790de572d98SGarrett D'Amore compilers[i], MFLAG, cfile, efile); 791de572d98SGarrett D'Amore test_debugf(t, "trying %s", cmd); 792de572d98SGarrett D'Amore rv = system(cmd); 793de572d98SGarrett D'Amore 794de572d98SGarrett D'Amore test_debugf(t, "result: %d", rv); 795de572d98SGarrett D'Amore 796de572d98SGarrett D'Amore if ((rv < 0) || !WIFEXITED(rv) || WEXITSTATUS(rv) != 0) 797de572d98SGarrett D'Amore continue; 798de572d98SGarrett D'Amore 799de572d98SGarrett D'Amore rv = system(efile); 800de572d98SGarrett D'Amore if (rv >= 0 && WIFEXITED(rv)) { 801de572d98SGarrett D'Amore rv = WEXITSTATUS(rv); 802de572d98SGarrett D'Amore } else { 803de572d98SGarrett D'Amore rv = -1; 804de572d98SGarrett D'Amore } 805de572d98SGarrett D'Amore 806de572d98SGarrett D'Amore switch (rv) { 807de572d98SGarrett D'Amore case 51: /* STUDIO */ 808de572d98SGarrett D'Amore test_debugf(t, "Found Studio C"); 809de572d98SGarrett D'Amore c89flags = "-Xc -errwarn=%all -v -xc99=%none " MFLAG; 810de572d98SGarrett D'Amore c99flags = "-Xc -errwarn=%all -v -xc99=%all " MFLAG; 811dcdfe824SRobert Mustacchi c11flags = NULL; 812de572d98SGarrett D'Amore if (extra_debug) { 813de572d98SGarrett D'Amore test_debugf(t, "c89flags: %s", c89flags); 814de572d98SGarrett D'Amore test_debugf(t, "c99flags: %s", c99flags); 815de572d98SGarrett D'Amore } 816de572d98SGarrett D'Amore test_passed(t); 817de572d98SGarrett D'Amore break; 818de572d98SGarrett D'Amore case 52: /* GCC */ 819de572d98SGarrett D'Amore test_debugf(t, "Found GNU C"); 820b599bd93SRobert Mustacchi c89flags = "-Wall -Werror -std=c89 -nostdinc " 821b599bd93SRobert Mustacchi "-isystem /usr/include " MFLAG; 822b599bd93SRobert Mustacchi c99flags = "-Wall -Werror -std=c99 -nostdinc " 823b599bd93SRobert Mustacchi "-isystem /usr/include " MFLAG; 824dcdfe824SRobert Mustacchi c11flags = "-Wall -Werror -std=c11 -nostdinc " 825dcdfe824SRobert Mustacchi "-isystem /usr/include " MFLAG; 826de572d98SGarrett D'Amore if (extra_debug) { 827de572d98SGarrett D'Amore test_debugf(t, "c89flags: %s", c89flags); 828de572d98SGarrett D'Amore test_debugf(t, "c99flags: %s", c99flags); 829de572d98SGarrett D'Amore } 830de572d98SGarrett D'Amore test_passed(t); 831de572d98SGarrett D'Amore break; 832de572d98SGarrett D'Amore case 99: 833de572d98SGarrett D'Amore test_debugf(t, "Found unknown (unsupported) compiler"); 834de572d98SGarrett D'Amore continue; 835de572d98SGarrett D'Amore default: 836de572d98SGarrett D'Amore continue; 837de572d98SGarrett D'Amore } 838de572d98SGarrett D'Amore myasprintf(&compiler, "%s", compilers[i]); 839de572d98SGarrett D'Amore test_debugf(t, "compiler: %s", compiler); 840de572d98SGarrett D'Amore return; 841de572d98SGarrett D'Amore } 842de572d98SGarrett D'Amore test_failed(t, "No compiler found."); 843de572d98SGarrett D'Amore } 844de572d98SGarrett D'Amore 845de572d98SGarrett D'Amore int 846de572d98SGarrett D'Amore do_compile(test_t t, struct sym_test *st, struct compile_env *cenv, int need) 847de572d98SGarrett D'Amore { 848de572d98SGarrett D'Amore char *cmd; 849de572d98SGarrett D'Amore FILE *logf; 850de572d98SGarrett D'Amore FILE *dotc; 851dcdfe824SRobert Mustacchi const char *prog, *cflags, *lang; 852de572d98SGarrett D'Amore 853de572d98SGarrett D'Amore full_count++; 854de572d98SGarrett D'Amore 855de572d98SGarrett D'Amore if ((dotc = fopen(cfile, "w+")) == NULL) { 856de572d98SGarrett D'Amore test_failed(t, "fopen(%s): %s", cfile, strerror(errno)); 857de572d98SGarrett D'Amore return (-1); 858de572d98SGarrett D'Amore } 859de572d98SGarrett D'Amore prog = sym_test_prog(st); 860de572d98SGarrett D'Amore if (fwrite(prog, 1, strlen(prog), dotc) < strlen(prog)) { 861de572d98SGarrett D'Amore test_failed(t, "fwrite: %s", strerror(errno)); 862de572d98SGarrett D'Amore (void) fclose(dotc); 863de572d98SGarrett D'Amore return (-1); 864de572d98SGarrett D'Amore } 865de572d98SGarrett D'Amore if (fclose(dotc) < 0) { 866de572d98SGarrett D'Amore test_failed(t, "fclose: %s", strerror(errno)); 867de572d98SGarrett D'Amore return (-1); 868de572d98SGarrett D'Amore } 869de572d98SGarrett D'Amore 870de572d98SGarrett D'Amore (void) unlink(ofile); 871de572d98SGarrett D'Amore 872dcdfe824SRobert Mustacchi if (strcmp(env_lang(cenv), "c99") == 0) { 873dcdfe824SRobert Mustacchi lang = "c99"; 874dcdfe824SRobert Mustacchi cflags = c99flags; 875dcdfe824SRobert Mustacchi } else if (strcmp(env_lang(cenv), "c11") == 0) { 876dcdfe824SRobert Mustacchi lang = "c11"; 877dcdfe824SRobert Mustacchi cflags = c11flags; 878dcdfe824SRobert Mustacchi } else { 879dcdfe824SRobert Mustacchi lang = "c89"; 880dcdfe824SRobert Mustacchi cflags = c89flags; 881dcdfe824SRobert Mustacchi } 882dcdfe824SRobert Mustacchi 883dcdfe824SRobert Mustacchi if (cflags == NULL) { 884dcdfe824SRobert Mustacchi test_failed(t, "compiler %s does not support %s", compiler, 885dcdfe824SRobert Mustacchi lang); 886dcdfe824SRobert Mustacchi return (-1); 887dcdfe824SRobert Mustacchi } 888dcdfe824SRobert Mustacchi 889de572d98SGarrett D'Amore myasprintf(&cmd, "%s %s %s -c %s -o %s >>%s 2>&1", 890dcdfe824SRobert Mustacchi compiler, cflags, env_defs(cenv), cfile, ofile, lfile); 891de572d98SGarrett D'Amore 892de572d98SGarrett D'Amore if (extra_debug) { 893de572d98SGarrett D'Amore test_debugf(t, "command: %s", cmd); 894de572d98SGarrett D'Amore } 895de572d98SGarrett D'Amore 896de572d98SGarrett D'Amore if ((logf = fopen(lfile, "w+")) == NULL) { 897de572d98SGarrett D'Amore test_failed(t, "fopen: %s", strerror(errno)); 898de572d98SGarrett D'Amore return (-1); 899de572d98SGarrett D'Amore } 900de572d98SGarrett D'Amore (void) fprintf(logf, "===================\n"); 901de572d98SGarrett D'Amore (void) fprintf(logf, "PROGRAM:\n%s\n", sym_test_prog(st)); 902de572d98SGarrett D'Amore (void) fprintf(logf, "COMMAND: %s\n", cmd); 903de572d98SGarrett D'Amore (void) fprintf(logf, "EXPECT: %s\n", need ? "OK" : "FAIL"); 904de572d98SGarrett D'Amore (void) fclose(logf); 905de572d98SGarrett D'Amore 906de572d98SGarrett D'Amore switch (system(cmd)) { 907de572d98SGarrett D'Amore case -1: 908de572d98SGarrett D'Amore test_failed(t, "error compiling in %s: %s", env_name(cenv), 909de572d98SGarrett D'Amore strerror(errno)); 910de572d98SGarrett D'Amore return (-1); 911de572d98SGarrett D'Amore case 0: 912de572d98SGarrett D'Amore if (!need) { 913de572d98SGarrett D'Amore fail_count++; 914de572d98SGarrett D'Amore show_file(t, lfile); 915de572d98SGarrett D'Amore test_failed(t, "symbol visible in %s", env_name(cenv)); 916de572d98SGarrett D'Amore return (-1); 917de572d98SGarrett D'Amore } 918de572d98SGarrett D'Amore break; 919de572d98SGarrett D'Amore default: 920de572d98SGarrett D'Amore if (need) { 921de572d98SGarrett D'Amore fail_count++; 922de572d98SGarrett D'Amore show_file(t, lfile); 923de572d98SGarrett D'Amore test_failed(t, "error compiling in %s", env_name(cenv)); 924de572d98SGarrett D'Amore return (-1); 925de572d98SGarrett D'Amore } 926de572d98SGarrett D'Amore break; 927de572d98SGarrett D'Amore } 928de572d98SGarrett D'Amore good_count++; 929de572d98SGarrett D'Amore return (0); 930de572d98SGarrett D'Amore } 931de572d98SGarrett D'Amore 932de572d98SGarrett D'Amore void 933de572d98SGarrett D'Amore test_compile(void) 934de572d98SGarrett D'Amore { 935de572d98SGarrett D'Amore struct sym_test *st; 936de572d98SGarrett D'Amore struct compile_env *cenv; 937de572d98SGarrett D'Amore test_t t; 938de572d98SGarrett D'Amore int need; 939de572d98SGarrett D'Amore 940de572d98SGarrett D'Amore for (st = next_sym_test(NULL); st; st = next_sym_test(st)) { 941de572d98SGarrett D'Amore if ((sym != NULL) && strcmp(sym, sym_test_name(st))) { 942de572d98SGarrett D'Amore continue; 943de572d98SGarrett D'Amore } 944de572d98SGarrett D'Amore /* XXX: we really want a sym_test_desc() */ 945de572d98SGarrett D'Amore for (cenv = sym_test_env(st, NULL, &need); 946de572d98SGarrett D'Amore cenv != NULL; 947de572d98SGarrett D'Amore cenv = sym_test_env(st, cenv, &need)) { 948de572d98SGarrett D'Amore t = test_start("%s : %c%s", sym_test_name(st), 949de572d98SGarrett D'Amore need ? '+' : '-', env_name(cenv)); 950de572d98SGarrett D'Amore if (do_compile(t, st, cenv, need) == 0) { 951de572d98SGarrett D'Amore test_passed(t); 952de572d98SGarrett D'Amore } 953de572d98SGarrett D'Amore } 954de572d98SGarrett D'Amore } 955de572d98SGarrett D'Amore 956de572d98SGarrett D'Amore if (full_count > 0) { 957de572d98SGarrett D'Amore test_summary(); 958de572d98SGarrett D'Amore } 959de572d98SGarrett D'Amore } 960de572d98SGarrett D'Amore 961de572d98SGarrett D'Amore int 962de572d98SGarrett D'Amore main(int argc, char **argv) 963de572d98SGarrett D'Amore { 964de572d98SGarrett D'Amore int optc; 965de572d98SGarrett D'Amore int optC = 0; 966de572d98SGarrett D'Amore 967de572d98SGarrett D'Amore while ((optc = getopt(argc, argv, "DdfCs:c:")) != EOF) { 968de572d98SGarrett D'Amore switch (optc) { 969de572d98SGarrett D'Amore case 'd': 970de572d98SGarrett D'Amore test_set_debug(); 971de572d98SGarrett D'Amore break; 972de572d98SGarrett D'Amore case 'f': 973de572d98SGarrett D'Amore test_set_force(); 974de572d98SGarrett D'Amore break; 975de572d98SGarrett D'Amore case 'D': 976de572d98SGarrett D'Amore test_set_debug(); 977de572d98SGarrett D'Amore extra_debug++; 978de572d98SGarrett D'Amore break; 979de572d98SGarrett D'Amore case 'c': 980de572d98SGarrett D'Amore compilation = optarg; 981de572d98SGarrett D'Amore break; 982de572d98SGarrett D'Amore case 'C': 983de572d98SGarrett D'Amore optC++; 984de572d98SGarrett D'Amore break; 985de572d98SGarrett D'Amore case 's': 986de572d98SGarrett D'Amore sym = optarg; 987de572d98SGarrett D'Amore break; 988de572d98SGarrett D'Amore default: 989de572d98SGarrett D'Amore (void) fprintf(stderr, "Usage: %s [-df]\n", argv[0]); 990de572d98SGarrett D'Amore exit(1); 991de572d98SGarrett D'Amore } 992de572d98SGarrett D'Amore } 993de572d98SGarrett D'Amore 994de572d98SGarrett D'Amore if (test_load_config(NULL, compilation, 995de572d98SGarrett D'Amore "env", do_env, "env_group", do_env_group, NULL) < 0) { 996de572d98SGarrett D'Amore exit(1); 997de572d98SGarrett D'Amore } 998de572d98SGarrett D'Amore 999de572d98SGarrett D'Amore while (optind < argc) { 1000de572d98SGarrett D'Amore if (test_load_config(NULL, argv[optind++], 1001de572d98SGarrett D'Amore "type", do_type, 1002de572d98SGarrett D'Amore "value", do_value, 1003dcdfe824SRobert Mustacchi "define", do_define, 1004de572d98SGarrett D'Amore "func", do_func, 1005de572d98SGarrett D'Amore NULL) < 0) { 1006de572d98SGarrett D'Amore exit(1); 1007de572d98SGarrett D'Amore } 1008de572d98SGarrett D'Amore } 1009de572d98SGarrett D'Amore 1010de572d98SGarrett D'Amore if (atexit(cleanup) != 0) { 1011de572d98SGarrett D'Amore perror("atexit"); 1012de572d98SGarrett D'Amore exit(1); 1013de572d98SGarrett D'Amore } 1014de572d98SGarrett D'Amore 1015dcdfe824SRobert Mustacchi if (custr_alloc(&st_custr) == -1) { 1016dcdfe824SRobert Mustacchi perror("custr"); 1017dcdfe824SRobert Mustacchi exit(1); 1018dcdfe824SRobert Mustacchi } 1019dcdfe824SRobert Mustacchi 1020de572d98SGarrett D'Amore if (mkworkdir() < 0) { 1021de572d98SGarrett D'Amore perror("mkdir"); 1022de572d98SGarrett D'Amore exit(1); 1023de572d98SGarrett D'Amore } 1024de572d98SGarrett D'Amore 1025de572d98SGarrett D'Amore find_compiler(); 1026de572d98SGarrett D'Amore if (!optC) 1027de572d98SGarrett D'Amore test_compile(); 1028de572d98SGarrett D'Amore 1029de572d98SGarrett D'Amore exit(0); 1030de572d98SGarrett D'Amore } 1031