diff options
Diffstat (limited to 'nim/extccomp.pas')
-rwxr-xr-x | nim/extccomp.pas | 676 |
1 files changed, 0 insertions, 676 deletions
diff --git a/nim/extccomp.pas b/nim/extccomp.pas deleted file mode 100755 index 7df3e8748..000000000 --- a/nim/extccomp.pas +++ /dev/null @@ -1,676 +0,0 @@ -// -// -// The Nimrod Compiler -// (c) Copyright 2009 Andreas Rumpf -// -// See the file "copying.txt", included in this -// distribution, for details about the copyright. -// -unit extccomp; - -// module for calling the different external C compilers - -interface - -{$include 'config.inc'} - -uses - nsystem, charsets, lists, ropes, nos, strutils, osproc, platform, condsyms, - options, msgs; - -// some things are read in from the configuration file - -type - TSystemCC = (ccNone, ccGcc, ccLLVM_Gcc, ccLcc, ccBcc, ccDmc, ccWcc, ccVcc, - ccTcc, ccPcc, ccUcc, ccIcc, ccGpp); - - TInfoCCProp = ( // properties of the C compiler: - hasSwitchRange, // CC allows ranges in switch statements (GNU C extension) - hasComputedGoto, // CC has computed goto (GNU C extension) - hasCpp, // CC is/contains a C++ compiler - hasAssume // CC has __assume (Visual C extension) - ); - TInfoCCProps = set of TInfoCCProp; - TInfoCC = record{@tuple} - name: string; // the short name of the compiler - objExt: string; // the compiler's object file extenstion - optSpeed: string; // the options for optimization for speed - optSize: string; // the options for optimization for size - compilerExe: string; // the compiler's executable - compileTmpl: string; // the compile command template - buildGui: string; // command to build a GUI application - buildDll: string; // command to build a shared library - linkerExe: string; // the linker's executable - linkTmpl: string; // command to link files to produce an executable - includeCmd: string; // command to add an include directory path - debug: string; // flags for debug build - pic: string; // command for position independent code - // used on some platforms - asmStmtFrmt: string; // format of ASM statement - props: TInfoCCProps; // properties of the C compiler - end; -const - CC: array [succ(low(TSystemCC))..high(TSystemCC)] of TInfoCC = ( - ( - name: 'gcc'; - objExt: 'o'+''; - optSpeed: ' -O3 -ffast-math '; - optSize: ' -Os -ffast-math '; - compilerExe: 'gcc'; - compileTmpl: '-c $options $include -o $objfile $file'; - buildGui: ' -mwindows'; - buildDll: ' -mdll'; - linkerExe: 'gcc'; - linkTmpl: '$options $buildgui $builddll -o $exefile $objfiles'; - includeCmd: ' -I'; - debug: ''; - pic: '-fPIC'; - asmStmtFrmt: 'asm($1);$n'; - props: {@set}[hasSwitchRange, hasComputedGoto, hasCpp]; - ), - ( - name: 'llvm_gcc'; - objExt: 'o'+''; - optSpeed: ' -O3 -ffast-math '; - optSize: ' -Os -ffast-math '; - compilerExe: 'llvm-gcc'; - compileTmpl: '-c $options $include -o $objfile $file'; - buildGui: ' -mwindows'; - buildDll: ' -mdll'; - linkerExe: 'llvm-gcc'; - linkTmpl: '$options $buildgui $builddll -o $exefile $objfiles'; - includeCmd: ' -I'; - debug: ''; - pic: '-fPIC'; - asmStmtFrmt: 'asm($1);$n'; - props: {@set}[hasSwitchRange, hasComputedGoto, hasCpp]; - ), - ( - name: 'lcc'; - objExt: 'obj'; - optSpeed: ' -O -p6 '; - optSize: ' -O -p6 '; - compilerExe: 'lcc'; - compileTmpl: '$options $include -Fo$objfile $file'; - buildGui: ' -subsystem windows'; - buildDll: ' -dll'; - linkerExe: 'lcclnk'; - linkTmpl: '$options $buildgui $builddll -O $exefile $objfiles'; - includeCmd: ' -I'; - debug: ' -g5 '; - pic: ''; - asmStmtFrmt: '_asm{$n$1$n}$n'; - props: {@set}[]; - ), - ( - name: 'bcc'; - objExt: 'obj'; - optSpeed: ' -O2 -6 '; - optSize: ' -O1 -6 '; - compilerExe: 'bcc32'; - compileTmpl: '-c $options $include -o$objfile $file'; - buildGui: ' -tW'; - buildDll: ' -tWD'; - linkerExe: 'bcc32'; - linkTmpl: '$options $buildgui $builddll -e$exefile $objfiles'; - includeCmd: ' -I'; - debug: ''; - pic: ''; - asmStmtFrmt: '__asm{$n$1$n}$n'; - props: {@set}[hasCpp]; - ), - ( - name: 'dmc'; - objExt: 'obj'; - optSpeed: ' -ff -o -6 '; - optSize: ' -ff -o -6 '; - compilerExe: 'dmc'; - compileTmpl: '-c $options $include -o$objfile $file'; - buildGui: ' -L/exet:nt/su:windows'; - buildDll: ' -WD'; - linkerExe: 'dmc'; - linkTmpl: '$options $buildgui $builddll -o$exefile $objfiles'; - includeCmd: ' -I'; - debug: ' -g '; - pic: ''; - asmStmtFrmt: '__asm{$n$1$n}$n'; - props: {@set}[hasCpp]; - ), - ( - name: 'wcc'; - objExt: 'obj'; - optSpeed: ' -ox -on -6 -d0 -fp6 -zW '; - optSize: ''; - compilerExe: 'wcl386'; - compileTmpl: '-c $options $include -fo=$objfile $file'; - buildGui: ' -bw'; - buildDll: ' -bd'; - linkerExe: 'wcl386'; - linkTmpl: '$options $buildgui $builddll -fe=$exefile $objfiles '; - includeCmd: ' -i='; - debug: ' -d2 '; - pic: ''; - asmStmtFrmt: '__asm{$n$1$n}$n'; - props: {@set}[hasCpp]; - ), - ( - name: 'vcc'; - objExt: 'obj'; - optSpeed: ' /Ogityb2 /G7 /arch:SSE2 '; - optSize: ' /O1 /G7 '; - compilerExe: 'cl'; - compileTmpl: '/c $options $include /Fo$objfile $file'; - buildGui: ' /link /SUBSYSTEM:WINDOWS '; - buildDll: ' /LD'; - linkerExe: 'cl'; - linkTmpl: '$options $builddll /Fe$exefile $objfiles $buildgui'; - includeCmd: ' /I'; - debug: ' /GZ /Zi '; - pic: ''; - asmStmtFrmt: '__asm{$n$1$n}$n'; - props: {@set}[hasCpp, hasAssume]; - ), - ( - name: 'tcc'; - objExt: 'o'+''; - optSpeed: ''; - optSize: ''; - compilerExe: 'tcc'; - compileTmpl: '-c $options $include -o $objfile $file'; - buildGui: 'UNAVAILABLE!'; - buildDll: ' -shared'; - linkerExe: 'tcc'; - linkTmpl: '-o $exefile $options $buildgui $builddll $objfiles'; - includeCmd: ' -I'; - debug: ' -g '; - pic: ''; - asmStmtFrmt: '__asm{$n$1$n}$n'; - props: {@set}[hasSwitchRange, hasComputedGoto]; - ), - ( - name: 'pcc'; // Pelles C - objExt: 'obj'; - optSpeed: ' -Ox '; - optSize: ' -Os '; - compilerExe: 'cc'; - compileTmpl: '-c $options $include -Fo$objfile $file'; - buildGui: ' -SUBSYSTEM:WINDOWS'; - buildDll: ' -DLL'; - linkerExe: 'cc'; - linkTmpl: '$options $buildgui $builddll -OUT:$exefile $objfiles'; - includeCmd: ' -I'; - debug: ' -Zi '; - pic: ''; - asmStmtFrmt: '__asm{$n$1$n}$n'; - props: {@set}[]; - ), - ( - name: 'ucc'; - objExt: 'o'+''; - optSpeed: ' -O3 '; - optSize: ' -O1 '; - compilerExe: 'cc'; - compileTmpl: '-c $options $include -o $objfile $file'; - buildGui: ''; - buildDll: ' -shared '; - linkerExe: 'cc'; - linkTmpl: '-o $exefile $options $buildgui $builddll $objfiles'; - includeCmd: ' -I'; - debug: ''; - pic: ''; - asmStmtFrmt: '__asm{$n$1$n}$n'; - props: {@set}[]; - ), ( - name: 'icc'; - objExt: 'o'+''; - optSpeed: ' -O3 '; - optSize: ' -Os '; - compilerExe: 'icc'; - compileTmpl: '-c $options $include -o $objfile $file'; - buildGui: ' -mwindows'; - buildDll: ' -mdll'; - linkerExe: 'icc'; - linkTmpl: '$options $buildgui $builddll -o $exefile $objfiles'; - includeCmd: ' -I'; - debug: ''; - pic: '-fPIC'; - asmStmtFrmt: 'asm($1);$n'; - props: {@set}[hasSwitchRange, hasComputedGoto, hasCpp]; - ), ( - name: 'gpp'; - objExt: 'o'+''; - optSpeed: ' -O3 -ffast-math '; - optSize: ' -Os -ffast-math '; - compilerExe: 'g++'; - compileTmpl: '-c $options $include -o $objfile $file'; - buildGui: ' -mwindows'; - buildDll: ' -mdll'; - linkerExe: 'g++'; - linkTmpl: '$options $buildgui $builddll -o $exefile $objfiles'; - includeCmd: ' -I'; - debug: ' -g '; - pic: '-fPIC'; - asmStmtFrmt: 'asm($1);$n'; - props: {@set}[hasSwitchRange, hasComputedGoto, hasCpp]; - ) - ); - -var - ccompiler: TSystemCC = ccGcc; // the used compiler - -const - hExt = 'h'+''; - -var - cExt: string = 'c'+''; // extension of generated C/C++ files - // (can be changed to .cpp later) - -function completeCFilePath(const cfile: string; - createSubDir: Boolean = true): string; - -function getCompileCFileCmd(const cfilename: string; - isExternal: bool = false): string; - -procedure addFileToCompile(const filename: string); -procedure addExternalFileToCompile(const filename: string); -procedure addFileToLink(const filename: string); - -procedure addCompileOption(const option: string); -procedure addLinkOption(const option: string); - -function toObjFile(const filenameWithoutExt: string): string; - -procedure CallCCompiler(const projectFile: string); - -procedure execExternalProgram(const cmd: string); - -function NameToCC(const name: string): TSystemCC; - -procedure initVars; - -procedure setCC(const ccname: string); -procedure writeMapping(gSymbolMapping: PRope); - -implementation - -var - toLink, toCompile, externalToCompile: TLinkedList; - linkOptions: string = ''; - compileOptions: string = ''; - - ccompilerpath: string = ''; - -procedure setCC(const ccname: string); -var - i: TSystemCC; -begin - ccompiler := nameToCC(ccname); - if ccompiler = ccNone then rawMessage(errUnknownCcompiler, ccname); - compileOptions := getConfigVar(CC[ccompiler].name + '.options.always'); - linkOptions := getConfigVar(CC[ccompiler].name + '.options.linker'); - ccompilerpath := getConfigVar(CC[ccompiler].name + '.path'); - for i := low(CC) to high(CC) do undefSymbol(CC[i].name); - defineSymbol(CC[ccompiler].name); -end; - -procedure initVars; -var - i: TSystemCC; -begin - // we need to define the symbol here, because ``CC`` may have never been set! - for i := low(CC) to high(CC) do undefSymbol(CC[i].name); - defineSymbol(CC[ccompiler].name); - if gCmd = cmdCompileToCpp then - cExt := '.cpp'; - addCompileOption(getConfigVar(CC[ccompiler].name + '.options.always')); - addLinkOption(getConfigVar(CC[ccompiler].name + '.options.linker')); - if length(ccompilerPath) = 0 then - ccompilerpath := getConfigVar(CC[ccompiler].name + '.path'); -end; - -function completeCFilePath(const cfile: string; - createSubDir: Boolean = true): string; -begin - result := completeGeneratedFilePath(cfile, createSubDir); -end; - -function NameToCC(const name: string): TSystemCC; -var - i: TSystemCC; -begin - for i := succ(ccNone) to high(TSystemCC) do - if cmpIgnoreStyle(name, CC[i].name) = 0 then begin - result := i; exit - end; - result := ccNone -end; - -procedure addOpt(var dest: string; const src: string); -begin - if (length(dest) = 0) or (dest[length(dest)-1+strStart] <> ' ') then - add(dest, ' '+''); - add(dest, src); -end; - -procedure addCompileOption(const option: string); -begin - if strutils.find(compileOptions, option, strStart) < strStart then - addOpt(compileOptions, option) -end; - -procedure addLinkOption(const option: string); -begin - if find(linkOptions, option, strStart) < strStart then - addOpt(linkOptions, option) -end; - -function toObjFile(const filenameWithoutExt: string): string; -begin - result := changeFileExt(filenameWithoutExt, cc[ccompiler].objExt) -end; - -procedure addFileToCompile(const filename: string); -begin - appendStr(toCompile, filename); -end; - -procedure addExternalFileToCompile(const filename: string); -begin - appendStr(externalToCompile, filename); -end; - -procedure addFileToLink(const filename: string); -begin - prependStr(toLink, filename); // BUGFIX - //appendStr(toLink, filename); -end; - -procedure execExternalProgram(const cmd: string); -begin - if (optListCmd in gGlobalOptions) or (gVerbosity > 0) then - MessageOut(cmd); - if execCmd(cmd) <> 0 then - rawMessage(errExecutionOfProgramFailed); -end; - -procedure generateScript(const projectFile: string; script: PRope); -var - path, scriptname, name, ext: string; -begin - splitPath(projectFile, path, scriptname); - SplitFilename(scriptname, name, ext); - name := addFileExt('compile_' + name, platform.os[targetOS].scriptExt); - WriteRope(script, joinPath(path, name)); -end; - -function getOptSpeed(c: TSystemCC): string; -begin - result := getConfigVar(cc[c].name + '.options.speed'); - if result = '' then - result := cc[c].optSpeed // use default settings from this file -end; - -function getDebug(c: TSystemCC): string; -begin - result := getConfigVar(cc[c].name + '.options.debug'); - if result = '' then - result := cc[c].debug // use default settings from this file -end; - -function getOptSize(c: TSystemCC): string; -begin - result := getConfigVar(cc[c].name + '.options.size'); - if result = '' then - result := cc[c].optSize // use default settings from this file -end; - -const - specialFileA = 42; - specialFileB = 42; -var - fileCounter: int; - -function getCompileCFileCmd(const cfilename: string; - isExternal: bool = false): string; -var - cfile, objfile, options, includeCmd, compilePattern, key, trunk, exe: string; - c: TSystemCC; // an alias to ccompiler -begin - c := ccompiler; - options := compileOptions; - trunk := splitFile(cfilename).name; - if optCDebug in gGlobalOptions then begin - key := trunk + '.debug'; - if existsConfigVar(key) then - addOpt(options, getConfigVar(key)) - else - addOpt(options, getDebug(c)) - end; - if (optOptimizeSpeed in gOptions) then begin - //if ((fileCounter >= specialFileA) and (fileCounter <= specialFileB)) then - key := trunk + '.speed'; - if existsConfigVar(key) then - addOpt(options, getConfigVar(key)) - else - addOpt(options, getOptSpeed(c)) - end - else if optOptimizeSize in gOptions then begin - key := trunk + '.size'; - if existsConfigVar(key) then - addOpt(options, getConfigVar(key)) - else - addOpt(options, getOptSize(c)) - end; - key := trunk + '.always'; - if existsConfigVar(key) then - addOpt(options, getConfigVar(key)); - - exe := cc[c].compilerExe; - key := cc[c].name + '.exe'; - if existsConfigVar(key) then - exe := getConfigVar(key); - if targetOS = osWindows then exe := addFileExt(exe, 'exe'); - - if (optGenDynLib in gGlobalOptions) - and (ospNeedsPIC in platform.OS[targetOS].props) then - add(options, ' ' + cc[c].pic); - - if targetOS = platform.hostOS then begin - // compute include paths: - includeCmd := cc[c].includeCmd; // this is more complex than needed, but - // a workaround of a FPC bug... - add(includeCmd, quoteIfContainsWhite(libpath)); - compilePattern := JoinPath(ccompilerpath, exe); - end - else begin - includeCmd := ''; - compilePattern := cc[c].compilerExe - end; - if targetOS = platform.hostOS then - cfile := cfilename - else - cfile := extractFileName(cfilename); - - if not isExternal or (targetOS <> platform.hostOS) then - objfile := toObjFile(cfile) - else - objfile := completeCFilePath(toObjFile(cfile)); - cfile := quoteIfContainsWhite(AddFileExt(cfile, cExt)); - objfile := quoteIfContainsWhite(objfile); - - result := quoteIfContainsWhite(format(compilePattern, - ['file', cfile, - 'objfile', objfile, - 'options', options, - 'include', includeCmd, - 'nimrod', getPrefixDir(), - 'lib', libpath - ])); - add(result, ' '); - add(result, format(cc[c].compileTmpl, - ['file', cfile, - 'objfile', objfile, - 'options', options, - 'include', includeCmd, - 'nimrod', quoteIfContainsWhite(getPrefixDir()), - 'lib', quoteIfContainsWhite(libpath) - ])); -end; - -procedure CompileCFile(const list: TLinkedList; - var script: PRope; - var cmds: TStringSeq; - isExternal: Boolean); -var - it: PStrEntry; - compileCmd: string; -begin - it := PStrEntry(list.head); - while it <> nil do begin - inc(fileCounter); - // call the C compiler for the .c file: - compileCmd := getCompileCFileCmd(it.data, isExternal); - if not (optCompileOnly in gGlobalOptions) then - add(cmds, compileCmd); //execExternalProgram(compileCmd); - if (optGenScript in gGlobalOptions) then begin - app(script, compileCmd); - app(script, tnl); - end; - it := PStrEntry(it.next); - end; -end; - -procedure CallCCompiler(const projectfile: string); -var - it: PStrEntry; - linkCmd, objfiles, exefile, buildgui, builddll, linkerExe: string; - c: TSystemCC; // an alias to ccompiler - script: PRope; - cmds: TStringSeq; - res, i: int; -begin - if (gGlobalOptions * [optCompileOnly, optGenScript] = [optCompileOnly]) then - exit; // speed up that call if only compiling and no script shall be - // generated - if (toCompile.head = nil) and (externalToCompile.head = nil) then exit; - fileCounter := 0; - c := ccompiler; - script := nil; - cmds := {@ignore} nil {@emit @[]}; - CompileCFile(toCompile, script, cmds, false); - CompileCFile(externalToCompile, script, cmds, true); - if not (optCompileOnly in gGlobalOptions) then begin - if gNumberOfProcessors = 0 then - gNumberOfProcessors := countProcessors(); - if gNumberOfProcessors <= 1 then begin - res := 0; - for i := 0 to high(cmds) do res := max(execCmd(cmds[i]), res); - end - else if (optListCmd in gGlobalOptions) or (gVerbosity > 0) then - res := execProcesses(cmds, {@set}[poEchoCmd, poUseShell, poParentStreams], - gNumberOfProcessors) - else - res := execProcesses(cmds, {@set}[poUseShell, poParentStreams], - gNumberOfProcessors); - if res <> 0 then - rawMessage(errExecutionOfProgramFailed); - end; - - if not (optNoLinking in gGlobalOptions) then begin - // call the linker: - linkerExe := getConfigVar(cc[c].name + '.linkerexe'); - if length(linkerExe) = 0 then linkerExe := cc[c].linkerExe; - if targetOS = osWindows then linkerExe := addFileExt(linkerExe, 'exe'); - - if (platform.hostOS <> targetOS) then - linkCmd := quoteIfContainsWhite(linkerExe) - else - linkCmd := quoteIfContainsWhite(JoinPath(ccompilerpath, linkerExe)); - - if optGenGuiApp in gGlobalOptions then - buildGui := cc[c].buildGui - else - buildGui := ''; - - if optGenDynLib in gGlobalOptions then begin - exefile := format(platform.os[targetOS].dllFrmt, - [splitFile(projectFile).name]); - buildDll := cc[c].buildDll; - end - else begin - exefile := splitFile(projectFile).name +{&} platform.os[targetOS].exeExt; - buildDll := ''; - end; - if targetOS = platform.hostOS then - exefile := joinPath(splitFile(projectFile).dir, exefile); - exefile := quoteIfContainsWhite(exefile); - - it := PStrEntry(toLink.head); - objfiles := ''; - while it <> nil do begin - add(objfiles, ' '+''); - if targetOS = platform.hostOS then - add(objfiles, quoteIfContainsWhite(toObjfile(it.data))) - else - add(objfiles, quoteIfContainsWhite( - toObjfile(extractFileName(it.data)))); - it := PStrEntry(it.next); - end; - - linkCmd := quoteIfContainsWhite(format(linkCmd, [ - 'builddll', builddll, - 'buildgui', buildgui, - 'options', linkOptions, - 'objfiles', objfiles, - 'exefile', exefile, - 'nimrod', getPrefixDir(), - 'lib', libpath - ])); - add(linkCmd, ' '); - add(linkCmd, format(cc[c].linkTmpl, [ - 'builddll', builddll, - 'buildgui', buildgui, - 'options', linkOptions, - 'objfiles', objfiles, - 'exefile', exefile, - 'nimrod', quoteIfContainsWhite(getPrefixDir()), - 'lib', quoteIfContainsWhite(libpath) - ])); - - if not (optCompileOnly in gGlobalOptions) then - execExternalProgram(linkCmd); - end // end if not noLinking - else - linkCmd := ''; - if (optGenScript in gGlobalOptions) then begin - app(script, linkCmd); - app(script, tnl); - generateScript(projectFile, script) - end -end; - -function genMappingFiles(const list: TLinkedList): PRope; -var - it: PStrEntry; -begin - result := nil; - it := PStrEntry(list.head); - while it <> nil do begin - appf(result, '--file:r"$1"$n', [toRope(AddFileExt(it.data, cExt))]); - it := PStrEntry(it.next); - end; -end; - -procedure writeMapping(gSymbolMapping: PRope); -var - code: PRope; -begin - if not (optGenMapping in gGlobalOptions) then exit; - code := toRope('[C_Files]'+nl); - app(code, genMappingFiles(toCompile)); - app(code, genMappingFiles(externalToCompile)); - appf(code, '[Symbols]$n$1', [gSymbolMapping]); - WriteRope(code, joinPath(projectPath, 'mapping.txt')); -end; - -end. |