#!/usr/local/bin/pike |
|
// RNTCC, a front-end to WatCOM C/C++ with options similar to GCC |
// Written by Fredrik Hubinette. |
|
inherit "lib.pike"; |
|
// Verbose is default for now, this can be turned off one this |
// frontend has been refined to where it does not require more |
// debugging. |
|
int verbose=1; |
|
// Temporary variable |
int linking_failed; |
|
string get_ext(string file) |
{ |
sscanf(file=lower_case(reverse(file)),"%s.",file); |
return reverse(file); |
} |
|
int compile(string *sources, |
string dest, |
string errorfile, |
string *cflags) |
{ |
int ret; |
mixed cmd; |
if(!dest) |
{ |
string tmp=reverse(sources[0]); |
sscanf(tmp,"%*s.%s",tmp); |
dest=reverse(tmp)+".o"; |
} |
|
dest=fixpath(dest); |
|
sources=Array.map(sources,fixpath); |
switch(get_ext(sources[0])) |
{ |
case "c": |
cmd=({ "wcc386" }) + cflags + ({"-fr"+errorfile, "-fo"+dest}) + sources; |
break; |
|
case "cpp": |
case "cc": |
cmd=({ "wpp386" }) + cflags + ({"-fr"+errorfile, "-fo"+dest}) + sources; |
break; |
|
case "s": |
cmd=({ "wasm", "-fe"+errorfile, "-fo"+dest,})+ sources; |
|
default: |
werror("Don't know how to compile %s\n",sources[0]); |
exit(1); |
} |
|
if(verbose) |
return do_cmd(cmd); |
else |
return silent_do_cmd(cmd); |
} |
|
string check_errorfile(string errorfile) |
{ |
object f=Stdio.File(); |
if(f->open(errorfile,"r")) |
{ |
string data; |
werror(data=f->read()); |
f->close(); |
data=replace(data,"\r",""); |
rm(errorfile); |
foreach(data/"\n", string line) |
{ |
if(!strlen(line)) continue; |
if(search(line,"Warning")!=-1) continue; |
werror("Error in compilation detected. "+line+"\n"); |
exit(1); |
} |
} |
} |
|
int main(int argc, string *argv) |
{ |
string target; |
string operation="link"; |
string *cflags=({"-d__WIN32__","-d_WIN32"}); |
string *ldopts=({"OPTION","STACK=8m"}); |
string *libraries=({}); |
string *objects=({}); |
string *sources=({}); |
int debug,optimize; |
string output; |
int share=0; |
|
mixed *opts=Getopt.find_all_options(argv, aggregate( |
({"oper_pre",Getopt.NO_ARG, ({"-E"}) }), |
({"oper_comp",Getopt.NO_ARG, ({"-c"}) }), |
({"verbose",Getopt.NO_ARG, ({"-v"}) }), |
({"debug",Getopt.MAY_HAVE_ARG, ({"-g"}) }), |
({"optimize",Getopt.MAY_HAVE_ARG, ({"-O"}) }), |
({"include",Getopt.HAS_ARG, ({"-I"}) }), |
({"link",Getopt.HAS_ARG, ({"-l"}) }), |
({"share",Getopt.MAY_HAVE_ARG, ({"-s"}) }), |
({"ignore",Getopt.MAY_HAVE_ARG, ({"-t"}) }), |
({"ignore",Getopt.HAS_ARG, ({"-R","-L","-r"}) }), |
({"warn",Getopt.MAY_HAVE_ARG, ({"-W"}) }), |
({"define",Getopt.HAS_ARG, ({"-D"}) }), |
({"undefine",Getopt.HAS_ARG, ({"-U"})}), |
({"output",Getopt.HAS_ARG, ({"-o"}) }), |
({"export",Getopt.HAS_ARG, ({"--export"}) }) |
)); |
foreach(opts, mixed *option) |
{ |
switch(option[0]) |
{ |
case "verbose": |
verbose++; |
break; |
|
case "export": |
ldopts+=({"export",option[1]+"_"}); |
break; |
|
case "share": |
share=1; |
ldopts=({"SYSTEM","nt_dll","initinstance","terminstance"})+ldopts; |
cflags+=({"-bd"}); |
break; |
|
case "oper_pre": operation="preprocess"; break; |
case "oper_comp": operation="compile"; break; |
case "debug": |
// cflags+=({"-d2"}); |
// ldopts+=({"DEBUG","WATCOM","ALL"}); |
|
cflags+=({"-d2","-hd"}); |
ldopts+=({"DEBUG","DWARF"}); |
|
// cflags+=({"-d2","-hc"}); |
// ldopts+=({"DEBUG","CODEVIEW","OPTION","CVPACK"}); |
debug=1; |
break; |
|
case "optimize": |
if(!option[1]) option[1]=1; |
switch(optimize=(int)option[1]) |
{ |
case 0: optimize=0; break; |
case 1: cflags+=({"-ox"}); break; |
case 2: cflags+=({"-otexan"}); break; |
case 3..: |
cflags+=({"-s", |
"-oe="+(optimize*30), |
"-ol+", |
"-oabhikmnrt"}); |
break; |
} |
break; |
|
case "include": |
// Avoid searching 'local' include dirs. |
// This is not a very pretty solution. |
if(sscanf(option[1],"/usr/include/%*s") || |
sscanf(option[1],"/usr/local/%*s")) |
break; |
|
cflags+=({"-i"+fixpath(option[1])}); |
break; |
|
case "link": |
// -lm and -lc are automatically handled by wlink |
if(option[1]=="m" || option[1]=="c") break; |
|
// We optimiza a little, no need to bring in the same |
// library many times in a row. |
if(!sizeof(libraries) || libraries[-1]!=option[1]) |
libraries+=({option[1]}); |
break; |
|
case "warn": |
if(option[1]) |
{ |
// This allows us to pass options to the linker |
if(sscanf(option[1],"l,%s",string tmp)) |
{ |
// This was done for my convenience, it can be taken |
// out once smartlink has been fixed to not use absoute |
// paths for the 'uname' binary. |
if(sscanf(tmp,"-rpath%*s")) break; |
|
ldopts+=({tmp}); |
break; |
} |
} |
|
// More options should be recognized, options which are not |
// recognized should generate warning/error messages. |
switch(option[1]) |
{ |
case "all": cflags+=({"-wx"}); break; |
default: cflags+=({"-w2"}); break; |
} |
break; |
|
case "define": cflags+=({"-d"+option[1]}); break; |
case "undefine": cflags+=({"-u"+option[1]}); break; |
case "output": |
output=option[1]; |
break; |
} |
} |
|
// Scan through the remaining arguments |
argv=Getopt.get_args(argv); |
foreach(argv[1..], string tmp) |
{ |
if(tmp[0]=='-') |
{ |
werror("Unrecognized option "+tmp+".\n"); |
exit(1); |
} |
|
// Recognize which files need to be compiled |
switch(get_ext(tmp)) |
{ |
case "o": |
case "a": |
case "obj": |
case "dll": |
case "lib": |
objects+=({tmp}); |
break; |
|
default: |
sources+=({tmp}); |
} |
} |
|
if(output) rm(output); |
|
string errorfile="tmp"+getpid()+".err"; |
rm(errorfile); |
|
// Flags required to make the compiler behave well |
cflags+=({"-bm","-zq","-sg","-5","-fpi87","-fp3"}); |
|
switch(operation) |
{ |
default: |
werror("Unknown operation "+operation+".\n"); |
exit(1); |
|
case "compile": |
compile(sources,output,errorfile,cflags); |
break; |
|
case "preprocess": |
{ |
switch(get_ext(sources[0])) |
{ |
default: |
case "c": |
int ret=silent_do_cmd( ({"wcc386","-p","-fr"+errorfile}) + cflags + Array.map(sources, fixpath)); |
break; |
|
case "cc": |
case "cpp": |
int ret=silent_do_cmd( ({"wpp386","-p","-fr"+errorfile}) + cflags + Array.map(sources, fixpath)); |
break; |
} |
break; |
} |
|
case "link": |
foreach(sources, string source) |
{ |
string obj=reverse(source); |
sscanf(obj,"%*s.%s",obj); |
obj=reverse(obj)+".obj"; |
|
compile( ({source}), obj, errorfile, cflags); |
objects+=({obj}); |
check_errorfile(errorfile); |
} |
|
// objects+=({"BINMODE.OBJ"}); |
string ldfile="TMP"+getpid()+".lk"; |
if(!output) output="a.out"; |
rm(ldfile); |
|
|
target=output; |
if(!share) target+=".exe"; |
|
string linkopts=("NAME "+target+" " + |
ldopts*" "+" "+ |
"FILE "+Array.map(objects,fixpath)*","+" "+ |
sprintf("%{LIBRARY %s %}",libraries)); |
Stdio.write_file(ldfile,linkopts); |
if(verbose) |
werror("DOING wlink "+linkopts+"\n"); |
|
#if 0 |
Process.system("cat "+ldfile); |
write("\n"); |
#endif |
linking_failed=0; |
|
silent_do_cmd( ({"wlink","@"+ldfile }), lambda(string data) |
{ |
if(search(data," W1008:")!=-1) |
linking_failed++; |
}); |
|
if(getenv("CLEANUP")!="no") |
rm(ldfile); |
|
if(linking_failed) exit(1); |
} |
|
check_errorfile(errorfile); |
|
if(target) |
{ |
if(!file_stat(target)) |
{ |
werror("RNTCC: output file not generated.\n"); |
exit(1); |
} |
} |
|
if(operation == "link" && !share) |
{ |
rm(output); |
Stdio.write_file(output, |
"#!/usr/local/bin/pike\n" |
"inherit \""+find_lib_location()+"\";\n" |
"int main(int argc, string *argv) {\n" |
"argv[0]+=\".exe\";\n" |
"argv[0]=getenv(\"NTDRIVE\")+fixpath(combine_path(getcwd(),argv[0]));\n" |
" exit(silent_do_cmd(argv));\n" |
"}\n"); |
chmod(output,0755); |
} |
exit(0); |
} |
|