github.com/singularityware/singularity@v3.1.1+incompatible/makeit/genmod.awk (about) 1 #!/usr/bin/awk -f 2 # Copyright (c) 2015-2018, Yannick Cote <yhcote@gmail.com>. All rights reserved. 3 # Use of this source code is governed by a BSD-style license that can be found 4 # in the LICENSE file. 5 6 function usage() 7 { 8 print "usage: genmod mconflist=<module file> makeitgendir=<temp confdir>" 9 print " host=<host type> tmpldir=<template location>" 10 exit(1) 11 } 12 13 # remove extra spaces from a string 14 function trim(str) 15 { 16 gsub(/ +/, " ", str) 17 gsub(/ +$/, "", str) 18 gsub(/^ +/, "", str) 19 20 return str 21 } 22 23 # print all keyword vars and their values for all project modules 24 function printmvars() 25 { 26 reset_file("/tmp/mvars") 27 for (m in mconfs) { 28 for (k in keywords) { 29 if (mvars[mconfs[m], keywords[k]] == "") 30 continue 31 printf("%s:%s [%s]\n", mconfs[m], keywords[k], 32 mvars[mconfs[m], keywords[k]]) >> "/tmp/mvars" 33 } 34 print "" >> "/tmp/mvars" 35 } 36 } 37 38 # truncate file 39 function reset_file(file) 40 { 41 printf("") > file 42 } 43 44 # check if we are still reading keyword values or reached a new keyword 45 function getkeyword() 46 { 47 iskey = 0 48 49 if (words[1] != "") { 50 for (k in keywords) { 51 if (words[1] == keywords[k]) 52 iskey = 1 53 } 54 if (iskey == 1) { 55 currkeywd = words[1] 56 } else { 57 print "error:", words[1], "is not a keyword" 58 exit(1) 59 } 60 } 61 } 62 63 # for a keyword (name, src, cflags, etc.) read its values 64 function getvalues(mconf, nfields) 65 { 66 for (j = 2; j <= nfields; j++) { 67 mvars[mconf, currkeywd] = mvars[mconf, currkeywd] " " words[j] 68 } 69 mvars[mconf, currkeywd] = trim(mvars[mconf, currkeywd]) 70 } 71 72 # this routine reads and parses all mconf variables from one "mconf" file 73 function scanmconf(mconf, makeitgendir) 74 { 75 m = makeitgendir "/" mconf ".parsed" 76 while (getline < m > 0) { 77 n = split($0, words, " *:= *| *\\ *|[ \t]*") 78 if (n > 0) { 79 getkeyword() 80 getvalues(mconf, n) 81 } 82 } 83 } 84 85 # generate object list from [a,c]src,win_[a,c]src,unix_[a,c]src for each module 86 function genobjs(mconf) 87 { 88 # first "[a,c]obj" 89 split(mvars[mconf, "csrc"], objs, " ") 90 for (o in objs) { 91 gsub(/\.c$/, ".o", objs[o]) 92 mvars[mconf, "cobj"] = mvars[mconf, "cobj"] "$(BUILDDIR)/" objs[o] " " 93 mvars[mconf, "cleanfiles"] = mvars[mconf, "cleanfiles"] " " "$(BUILDDIR)/" objs[o] 94 mvars[mconf, "cleanfiles"] = mvars[mconf, "cleanfiles"] " " "$(BUILDDIR)/" objs[o] ".d" 95 } 96 97 split(mvars[mconf, "asrc"], objs, " ") 98 for (o in objs) { 99 gsub(/\.S$/, ".o", objs[o]) 100 mvars[mconf, "aobj"] = mvars[mconf, "aobj"] "$(BUILDDIR)/" objs[o] " " 101 mvars[mconf, "cleanfiles"] = mvars[mconf, "cleanfiles"] " " "$(BUILDDIR)/" objs[o] 102 mvars[mconf, "cleanfiles"] = mvars[mconf, "cleanfiles"] " " "$(BUILDDIR)/" objs[o] ".d" 103 } 104 105 # then "unix_[a,c]obj" 106 split(mvars[mconf, "unix_csrc"], objs, " ") 107 for (o in objs) { 108 gsub(/\.c$/, ".o", objs[o]) 109 mvars[mconf, "unix_cobj"] = mvars[mconf, "unix_cobj"] "$(BUILDDIR)/" objs[o] " " 110 mvars[mconf, "cleanfiles"] = mvars[mconf, "cleanfiles"] " " "$(BUILDDIR)/" objs[o] 111 mvars[mconf, "cleanfiles"] = mvars[mconf, "cleanfiles"] " " "$(BUILDDIR)/" objs[o] ".d" 112 } 113 114 split(mvars[mconf, "unix_asrc"], objs, " ") 115 for (o in objs) { 116 gsub(/\.S$/, ".o", objs[o]) 117 mvars[mconf, "unix_aobj"] = mvars[mconf, "unix_aobj"] "$(BUILDDIR)/" objs[o] " " 118 mvars[mconf, "cleanfiles"] = mvars[mconf, "cleanfiles"] " " "$(BUILDDIR)/" objs[o] 119 mvars[mconf, "cleanfiles"] = mvars[mconf, "cleanfiles"] " " "$(BUILDDIR)/" objs[o] ".d" 120 } 121 122 # then "win_[a,c]obj" 123 split(mvars[mconf, "win_csrc"], objs, " ") 124 for (o in objs) { 125 gsub(/\.c$/, ".o", objs[o]) 126 mvars[mconf, "win_cobj"] = mvars[mconf, "win_cobj"] "$(BUILDDIR)/" objs[o] " " 127 mvars[mconf, "cleanfiles"] = mvars[mconf, "cleanfiles"] " " "$(BUILDDIR)/" objs[o] 128 mvars[mconf, "cleanfiles"] = mvars[mconf, "cleanfiles"] " " "$(BUILDDIR)/" objs[o] ".d" 129 } 130 131 split(mvars[mconf, "win_asrc"], objs, " ") 132 for (o in objs) { 133 gsub(/\.S$/, ".o", objs[o]) 134 mvars[mconf, "win_aobj"] = mvars[mconf, "win_aobj"] "$(BUILDDIR)/" objs[o] " " 135 mvars[mconf, "cleanfiles"] = mvars[mconf, "cleanfiles"] " " "$(BUILDDIR)/" objs[o] 136 mvars[mconf, "cleanfiles"] = mvars[mconf, "cleanfiles"] " " "$(BUILDDIR)/" objs[o] ".d" 137 } 138 139 # finally "data" 140 split(mvars[mconf, "data"], objs, " ") 141 for (o in objs) { 142 objs[o] = objs[o] ".bin" 143 mvars[mconf, "dobj"] = mvars[mconf, "dobj"] objs[o] " " 144 mvars[mconf, "cleanfiles"] = mvars[mconf, "cleanfiles"] " " "$(BUILDDIR)/" objs[o] 145 } 146 } 147 148 # create the "target" mconf variable based on kind (prog, lib, obj list) 149 function gentarget(mconf) 150 { 151 if (mvars[mconf, "prog"] != "") { 152 # generate target for a program 153 mvars[mconf, "target"] = mvars[mconf, "prog"] 154 if (envar["host"] == "windows") 155 mvars[mconf, "target"] = mvars[mconf, "target"] ".exe" 156 } else if (mvars[mconf, "lib"] != "") { 157 # generate target for a library 158 mvars[mconf, "target"] = "lib" mvars[mconf, "lib"] 159 } else if (mvars[mconf, "data"] != "") { 160 # generate target for embedded data 161 mvars[mconf, "target"] = mvars[mconf, "name"] ".bin.o" 162 } else { 163 # generate target for a simple list of objects 164 mvars[mconf, "target"] = mvars[mconf, "name"] "_OBJ" 165 } 166 } 167 168 # create a list of "deps_link" list based on other mconf target this mconf needs to link with 169 function gendeps_link(mconf, idx) 170 { 171 # dependency is a program nothing to link with 172 if (mvars[mconfs[mconf], "prog"] != "") 173 return 174 175 # dependency is a lib, generate library link rules 176 if (mvars[mconfs[mconf], "lib"] != "") { 177 mvars[mconfs[idx], "deps_link"] = mvars[mconfs[idx], "deps_link"] " " \ 178 "-L$(BUILDDIR)/" mconfsdirs[mconf] " -l" mvars[mconfs[mconf], "lib"] 179 } else if (mvars[mconfs[mconf], "data"] != "") { 180 mvars[mconfs[idx], "extralibs"] = "$(" mvars[mconfs[mconf], "target"] ")" " " \ 181 mvars[mconfs[idx], "extralibs"] 182 } else { 183 # dependency is just an object list 184 mvars[mconfs[idx], "deps_link"] = "$(" mvars[mconfs[mconf], "target"] ")" " " \ 185 mvars[mconfs[idx], "deps_link"] 186 } 187 } 188 189 # create a "deps_target" list based on other mconf targets this mconf depends on 190 function gendeps(idx) 191 { 192 split(mvars[mconfs[idx], "depends"], deps, " ") 193 for (d in deps) { 194 found = 0 195 for (m in mconfs) { 196 if (mvars[mconfs[m], "name"] == deps[d]) { 197 gendeps_link(m, idx) 198 mvars[mconfs[idx], "deps_target"] = mvars[mconfs[idx], "deps_target"] " " \ 199 "$(" mvars[mconfs[m], "target"] ")" 200 found = 1 201 } 202 } 203 # if dependency is NOT a module name but just a verbatim expression to paste in place 204 if (found == 0) { 205 mvars[mconfs[idx], "deps_target"] = mvars[mconfs[idx], "deps_target"] " " deps[d] 206 } 207 } 208 mvars[mconfs[idx], "deps_link"] = trim(mvars[mconfs[idx], "deps_link"]) 209 mvars[mconfs[idx], "deps_target"] = trim(mvars[mconfs[idx], "deps_target"]) 210 } 211 212 # output all object lists rules for a specific .mconf file 213 function put_objlist(mconf, cobj, aobj, output) 214 { 215 printf("# object files list\n") >> output 216 printf("%s_OBJ := \\\n", mvars[mconf, "name"]) >> output 217 218 split(cobj, objs, " ") 219 for (o in objs) { 220 printf("\t%s \\\n", objs[o]) >> output 221 } 222 split(aobj, objs, " ") 223 for (o in objs) { 224 printf("\t%s \\\n", objs[o]) >> output 225 } 226 split(mvars[mconf, "dobj"], objs, " ") 227 for (o in objs) { 228 printf("\t%s \\\n", objs[o]) >> output 229 } 230 print "" >> output 231 } 232 233 # output all suffix (build) rules for a specific .mconf file 234 function put_suffix_rules(cobj, aobj, mconf, output) 235 { 236 printf("# suffix rules (metarules missing from most variants)\n") >> output 237 238 split(cobj, objs, " ") 239 for (o in objs) { 240 # prepare the source file name `s' out of `o' 241 s = objs[o] 242 gsub(/\.o$/, ".c", s) 243 gsub(/^\$\(BUILDDIR\)\//, "", s) 244 245 # fix up the target template when building generated source files 246 if (match(s, /^\$\(BUILDDIR\)\//) == 1) { 247 tmpl = envar["tmpldir"] "/" "suffix_bldir.tmpl" 248 n = split(s, gen, "/") 249 while (getline < tmpl > 0) { 250 gsub(/__OBJ__/, objs[o], $0) 251 gsub(/__SRC__/, s, $0) 252 gsub(/__GENSRC__/, "[GEN] " gen[n], $0) 253 gsub(/__CFLAGS__/, mvars[mconf, "cflags"], $0) 254 # write the result down in the current fragment 255 if ($0 != "") { 256 $0 = trim($0) 257 printf("%s\n", $0) >> output 258 } 259 } 260 close(tmpl) 261 } else { 262 tmpl = envar["tmpldir"] "/" "suffix.tmpl" 263 while (getline < tmpl > 0) { 264 gsub(/__OBJ__/, objs[o], $0) 265 gsub(/__SRC__/, s, $0) 266 gsub(/__CFLAGS__/, mvars[mconf, "cflags"], $0) 267 # write the result down in the current fragment 268 if ($0 != "") { 269 $0 = trim($0) 270 printf("%s\n", $0) >> output 271 } 272 } 273 close(tmpl) 274 } 275 } 276 split(aobj, objs, " ") 277 for (o in objs) { 278 # prepare the source file name `s' out of `o' 279 s = objs[o] 280 gsub(/\.o$/, ".S", s) 281 gsub(/^\$\(BUILDDIR\)\//, "", s) 282 283 # fix up the target template when building generated source files 284 if (match(s, /^\$\(BUILDDIR\)\//) == 1) { 285 tmpl = envar["tmpldir"] "/" "suffix_bldir.tmpl" 286 n = split(s, gen, "/") 287 while (getline < tmpl > 0) { 288 gsub(/__OBJ__/, objs[o], $0) 289 gsub(/__SRC__/, s, $0) 290 gsub(/__GENSRC__/, "[GEN] " gen[n], $0) 291 gsub(/__CFLAGS__/, mvars[mconf, "cflags"], $0) 292 # write the result down in the current fragment 293 if ($0 != "") { 294 $0 = trim($0) 295 printf("%s\n", $0) >> output 296 } 297 } 298 close(tmpl) 299 } else { 300 tmpl = envar["tmpldir"] "/" "suffix.tmpl" 301 while (getline < tmpl > 0) { 302 gsub(/__OBJ__/, objs[o], $0) 303 gsub(/__SRC__/, s, $0) 304 gsub(/__CFLAGS__/, mvars[mconf, "cflags"], $0) 305 # write the result down in the current fragment 306 if ($0 != "") { 307 $0 = trim($0) 308 printf("%s\n", $0) >> output 309 } 310 } 311 close(tmpl) 312 } 313 } 314 split(mvars[mconf, "dobj"], objs, " ") 315 for (o in objs) { 316 # prepare the source file name `s' out of `o' 317 s = objs[o] 318 gsub(/\.bin$/, "", s) 319 gsub(/^\$\(BUILDDIR\)\//, "", s) 320 321 tmpl = envar["tmpldir"] "/" "suffix_data.tmpl" 322 n = split(s, gen, "/") 323 while (getline < tmpl > 0) { 324 gsub(/__OBJ__/, objs[o], $0) 325 gsub(/__SRC__/, s, $0) 326 # write the result down in the current fragment 327 if ($0 != "") { 328 $0 = trim($0) 329 printf("%s\n", $0) >> output 330 } 331 } 332 close(tmpl) 333 } 334 335 print "" >> output 336 } 337 338 # output a "prog" target 339 function put_prog(mconf, mconfdir, output) 340 { 341 tmpl = envar["tmpldir"] "/" "prog.tmpl" 342 prefix = "" 343 344 printf("# link the program `%s'\n", mvars[mconf, "target"]) >> output 345 while (getline < tmpl > 0) { 346 gsub(/__TARGET__/, mvars[mconf, "target"], $0) 347 gsub(/__PATH__/, mconfdir, $0) 348 gsub(/__NAME__/, mvars[mconf, "name"], $0) 349 gsub(/__DEPEND_T__/, mvars[mconf, "deps_target"], $0) 350 gsub(/__DEPEND_L__/, mvars[mconf, "deps_link"], $0) 351 gsub(/__LDFLAGS__/, mvars[mconf, "ldflags"], $0) 352 gsub(/__EXTRALIBS__/, mvars[mconf, "extralibs"], $0) 353 $0 = trim($0) 354 printf("%s\n", $0) >> output 355 } 356 close(tmpl) 357 print "" >> output 358 359 mvars[mconf, "cleanfiles"] = mvars[mconf, "cleanfiles"] " " "$(" mvars[mconf, "target"] ")" 360 } 361 362 # output a "lib" target 363 function put_lib(mconf, mconfdir, output) 364 { 365 tmpl = envar["tmpldir"] "/" "lib.tmpl" 366 367 printf("# create lib `%s'\n", mvars[mconf, "target"]) >> output 368 while (getline < tmpl > 0) { 369 gsub(/__TARGET__/, mvars[mconf, "target"], $0) 370 gsub(/__PATH__/, mconfdir, $0) 371 gsub(/__NAME__/, mvars[mconf, "name"], $0) 372 $0 = trim($0) 373 printf("%s\n", $0) >> output 374 } 375 close(tmpl) 376 print "" >> output 377 378 mvars[mconf, "cleanfiles"] = mvars[mconf, "cleanfiles"] " " "$(" mvars[mconf, "target"] ")" 379 } 380 381 # output a "data" target 382 function put_data(mconf, mconfdir, output) 383 { 384 tmpl = envar["tmpldir"] "/" "data.tmpl" 385 386 printf("# create embedded data object `%s'\n", mvars[mconf, "target"]) >> output 387 while (getline < tmpl > 0) { 388 gsub(/__TARGET__/, mvars[mconf, "target"], $0) 389 gsub(/__PATH__/, mconfdir, $0) 390 gsub(/__NAME__/, mvars[mconf, "name"], $0) 391 $0 = trim($0) 392 printf("%s\n", $0) >> output 393 } 394 close(tmpl) 395 print "" >> output 396 397 mvars[mconf, "cleanfiles"] = mvars[mconf, "cleanfiles"] " " "$(" mvars[mconf, "target"] ")" 398 } 399 400 # generate 1 .mk file for specified .mconf -- to be inlined in top Makefile 401 function put_mkfile(mconf, mconfdir, output) 402 { 403 # gather objects from C files 404 cob = mvars[mconf, "cobj"] 405 if (envar["host"] == "unix") 406 cob = cob " " mvars[mconf, "unix_cobj"] 407 if (envar["host"] == "windows") 408 cob = cob " " mvars[mconf, "win_cobj"] 409 410 # gather objects from assembly .S files 411 aob = mvars[mconf, "aobj"] 412 if (envar["host"] == "unix") 413 aob = aob " " mvars[mconf, "unix_aobj"] 414 if (envar["host"] == "windows") 415 aob = aob " " mvars[mconf, "win_aobj"] 416 417 # write list of objects to build 418 put_objlist(mconf, cob, aob, output) 419 420 # if the mconf module is a program, write link rules 421 if (mvars[mconf, "prog"] != "") 422 put_prog(mconf, mconfdir, output) 423 424 # if the mconf module is a library, write lib creation rules 425 if (mvars[mconf, "lib"] != "") 426 put_lib(mconf, mconfdir, output) 427 428 # if the mconf module is embedded data objects, write data object creation rules 429 if (mvars[mconf, "data"] != "") 430 put_data(mconf, mconfdir, output) 431 432 # write each object suffix build rules 433 put_suffix_rules(cob, aob, mconf, output) 434 } 435 436 # generate the all: rule starting with loose targets, then libs, then programs in that order 437 # then generate the CLEANFILES rule 438 function genallrule(output) 439 { 440 combined_mconfsfile = envar["makeitgendir"] "/combined-mconfsready.mk" 441 reset_file(combined_mconfsfile) 442 443 printf("all:") > output 444 # write targets that are NOT libraries of programs first 445 for (m in mconfs) { 446 if (mvars[mconfs[m], "prog"] == "" && mvars[mconfs[m], "lib"] == "") { 447 printf(" $(%s)", mvars[mconfs[m], "target"]) >> output 448 put_mkfile(mconfs[m], mconfsdirs[m], combined_mconfsfile) 449 } 450 } 451 # then libraries 452 for (m in mconfs) { 453 if (mvars[mconfs[m], "lib"] != "") { 454 printf(" $(%s)", mvars[mconfs[m], "target"]) >> output 455 put_mkfile(mconfs[m], mconfsdirs[m], combined_mconfsfile) 456 } 457 } 458 # finally programs 459 for (m in mconfs) { 460 if (mvars[mconfs[m], "prog"] != "") { 461 printf(" $(%s)", mvars[mconfs[m], "target"]) >> output 462 put_mkfile(mconfs[m], mconfsdirs[m], combined_mconfsfile) 463 } 464 } 465 466 # collect cleanfiles from all mconfs and set a CLEANFILES make var 467 for (m in mconfs) { 468 cl = cl " " mvars[mconfs[m], "cleanfiles"] " " 469 } 470 cl = trim(cl) 471 printf("\n\nCLEANFILES += %s\n", cl) >> output 472 } 473 474 # check the parameters passed to the program 475 function checkvars() 476 { 477 if (envar["mconflist"] == "") 478 usage() 479 if (envar["host"] == "") 480 usage() 481 if (envar["makeitgendir"] == "") 482 usage() 483 if (envar["tmpldir"] == "") 484 usage() 485 } 486 487 # main entry 488 BEGIN { 489 # variable defs 490 mconfs[0] = "" 491 mconfsdirs[0] = "" 492 nmconfs = 0 493 mvars[0] = "" 494 words[0] = "" 495 currkeywd = "" 496 envar[0] = "" 497 keywords[0] = "" 498 klist = "name prog lib asrc data csrc win_asrc win_csrc unix_asrc unix_csrc" 499 klist = klist " " "depends cflags ldflags extralibs cleanfiles" 500 501 # init keywords 502 split(klist, keywords, " ") 503 504 # collect program environment vars from command line ARGV array 505 for (i = 0; i < ARGC; i++) { 506 n = split(ARGV[i], args, "=") 507 if (n == 2) 508 envar[args[1]] = args[2] 509 } 510 511 # check that we were called with all needed environment vars 512 checkvars() 513 514 # extract mconf dirname and basename from mconfig generated module.lst 515 while (getline < envar["mconflist"] > 0) { 516 mconfs[nmconfs] = $1 "/" $2 517 mconfsdirs[nmconfs] = $1 518 nmconfs++ 519 } 520 521 # for all .mconf files found, 1) parse, 2) gen src/obj lists, 3) gen make targets 522 for (i = 0; i < nmconfs; i++) { 523 scanmconf(mconfs[i], envar["makeitgendir"]) 524 genobjs(mconfs[i]) 525 gentarget(mconfs[i]) 526 } 527 528 # for each make targets generated above, generate dependency rules 529 for (i = 0; i < nmconfs; i++) { 530 gendeps(i) 531 } 532 533 # finally, generate the "all:" rule listing all target in dependency order 534 genallrule(envar["makeitgendir"] "/" "all.mk") 535 536 # printmvars() 537 }