diff --git a/cdc.d b/cdc.d deleted file mode 100755 index bce1388..0000000 --- a/cdc.d +++ /dev/null @@ -1,669 +0,0 @@ -#!/usr/bin/rdmd - -/** - * License: Boost 1.0 - * - * Copyright (c) 2009-2010 Eric Poggel, Changes 2011 Ferdinand Majerech - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * Description: - * - * This is a D programming language build script (and library) that can be used - * to compile D (version 1) source code. Unlike Bud, DSSS/Rebuild, Jake, and - * similar tools, CDC is contained within a single file that can easily be - * distributed with projects. This simplifies the build process since no other - * tools are required. The main() function can be utilized to turn - * CDC into a custom build script for your project. - * - * CDC's only requirement is a D compiler. It is/will be supported on any - * operating system supported by the language. It works with dmd, ldc (soon), - * and gdc. - * - * CDC can be used just like dmd, except for the following improvements. - * - - * These DMD/LDC options are automatically translated to the correct GDC - * options, or handled manually: - *
- *
-c
do not link
- *
-D
generate documentation
- *
-Dddocdir
write fully-qualified documentation files to docdir directory
- *
-Dfdocfile
write fully-qualified documentation files to docfile file
- *
-lib
Generate library rather than object files
- *
-Ipath
where to look for imports
- *
-o-
do not write object file.
- *
-offilename
name output file to filename
- *
-odobjdir
write object & library files to directory objdir
- *
- * - * In addition, these optional flags have been added. - *
- *
--dmd
Use dmd to compile
- *
--gdc
Use gdc to compile
- *
--ldc
Use ldc to compile
- *
- * - * Bugs: - * - * - * TODO: - * - * - * API: - * Use any of these functions in your own build script. - */ - - -import core.stdc.stdlib; - -import std.algorithm; -import std.array; -import std.exception; -import std.conv; -import std.file; -import std.path; -import std.process; -import std.range; -import std.string; -import std.stdio : writeln; - -alias std.process.system system; - - -///Name of the default compiler, which is the compiler used to build cdc. -version(DigitalMars){string compiler = "dmd";} -version(GNU){string compiler = "gdmd";} -version(LDC){string compiler = "ldmd2";} - -version(Windows) -{ - ///Valid object file extensions. - const string[] obj_ext = ["obj", "o"]; - ///Library extension. - const string lib_ext = "lib"; - ///Binary executable extension. - const string bin_ext = "exe"; - ///Path separator character. - char file_separator ='\\'; -} -else -{ - ///Valid object file extensions. - const string[] obj_ext = ["o"]; - ///Library extension. - const string lib_ext = "a"; - ///Binary executable extension. - const string bin_ext = ""; - ///Path separator character. - char file_separator ='/'; -} - -void main(string[] args) -{ - scope(failure){help(); core.stdc.stdlib.exit(-1);} - - string[] targets; - string[] extra_args = ["-w", "-wi"]; - - args = args[1 .. $]; - foreach(arg; args) - { - if(arg[0] == '-') switch(arg) - { - case "--help", "-h": help(); return; - case "--dmd": compiler = "dmd"; break; - case "--gdc": compiler = "gdmd"; break; - case "--ldc": compiler = "ldmd2"; break; - default: extra_args ~= arg; - } - else - { - targets ~= arg; - } - } - - if(targets.length == 0){targets = ["release"];} - - auto dbg = ["-debug", "-gc"]; - auto optimize = ["-O", "-inline", "-release", "-noboundscheck"]; - auto profile = ["-O", "-release", "-noboundscheck", "-gc"]; - auto lib_src = ["source"]; - - void compile_(string[] args, string[] files) - { - compile(args ~ extra_args, files); - } - - void build_unittest() - { - writeln("building unittests"); - compile_(dbg ~ ["-unittest", "-ofunittest"], lib_src ~ "unittest.d" ~ "test/src"); - } - - void build_debug() - { - writeln("building debug target"); - compile_(dbg ~ ["-oflibdyaml-debug", "-lib"], lib_src); - } - - void build_release() - { - writeln("building release target"); - compile_(optimize ~ ["-oflibdyaml", "-lib"], lib_src); - } - - void build_profile() - { - writeln("building profile target"); - compile_(profile ~ ["-oflibdyaml", "-lib"], lib_src); - } - - void build_tar_gz() - { - if(system("git archive HEAD | gzip -9v > dyaml.tar.gz") != 0) - { - writeln("Error creating a tar.gz package."); - } - } - - void build_tar_xz() - { - if(system("git archive HEAD | xz -9ev > dyaml.tar.xz ") != 0) - { - writeln("Error creating a tar.xz package."); - } - } - - void build_zip() - { - if(system("git archive -odyaml.zip -9 HEAD") != 0) - { - writeln("Error creating a zip package"); - } - } - - void build(string[] targets ...) - { - foreach(target; targets) switch(target) - { - case "debug": build_debug(); break; - case "release": build_release(); break; - case "profile": build_profile(); break; - case "unittest": build_unittest(); break; - case "tar.gz": build_tar_gz(); break; - case "tar.xz": build_tar_xz(); break; - case "zip": build_zip(); break; - case "all": build("debug", "release", "unittest"); break; - default: - writeln("unknown build target: ", target); - writeln("available targets: 'debug', 'release', 'profile', " - "'all', 'unittest', 'tar.gz', 'tar.xz', 'zip'"); - } - } - - try{build(targets);} - catch(CompileException e){writeln("Could not compile: " ~ e.msg);} - catch(ProcessException e){writeln("Compilation failed: " ~ e.msg);} - - writeln("DONE"); -} - -///Print help information. -void help() -{ - string help = - "D:YAML build script\n" - "Changes Copyright (C) 2011 Ferdinand Majerech\n" - "Based on CDC script Copyright (C) 2009-2010 Eric Poggel\n" - "Usage: cdc [OPTION ...] [EXTRA COMPILER OPTION ...] [TARGET ...]\n" - "By default, cdc uses the compiler it was built with to compile the project.\n" - "\n" - "Any options starting with '-' not parsed by the script will be\n" - "passed to the compiler used.\n" - "\n" - "Optionally, build target can be specified, 'debug' is default.\n" - "Available build targets:\n" - " unittest Build unit tests.\n" - " debug Debug information, unittests, contracts built in.\n" - " No optimizations.\n" - " release No debug information, no unittests, contracts.\n" - " Optimizations, inlining enabled.\n" - " profile Debug information, no unittests, contracts.\n" - " Optimizations, inlining enabled.\n" - " all Unittest, debug and release.\n" - " tar.gz Needs git, gzip: Create a tar.gz package.\n" - " tar.xz Needs git, xz: Create a tar.xz package.\n" - " zip Needs zip: Create a zip package.\n" - "\n" - "Available options:\n" - " -h --help Show this help information.\n" - " --gdc Use GDC for compilation.\n" - " --dmd Use DMD for compilation.\n" - " --ldc Use LDC for compilation. (not tested)\n" - ; - writeln(help); -} - -/** - * Compile D code using the current compiler. - * - * Params: options = Compiler options. - * paths = Source and library files/directories. Directories are recursively searched. - * - * Example: - * -------- - * //Compile all source files in src/core along with src/main.d, - * //link with all library files in the libs folder - * //and generate documentation in the docs folder. - * compile(["src/core", "src/main.d", "libs"], ["-D", "-Dddocs"]); - * -------- - * - * TODO Add a dry run option to just return an array of commands to execute. - */ -void compile(string[] options, string[] paths) -{ - //Convert src and lib paths to files - string[] sources, libs, ddocs; - foreach(src; paths) - { - enforceEx!CompileException(exists(src), - "Source file/folder \"" ~ src ~ "\" does not exist."); - //Directory of source or lib files - if(isDir(src)) - { - sources ~= scan(src, ".d"); - ddocs ~= scan(src, ".ddoc"); - libs ~= scan(src, lib_ext); - } - //File - else if(isFile(src)) - { - string ext = src.extension(); - if(ext == ".d"){sources ~= src;} - else if(ext == lib_ext){libs ~= src;} - } - } - - //Add dl.a for dynamic linking on linux - version(linux){libs ~= ["-L-ldl"];} - - //Combine all options, sources, ddocs, and libs - CompileOptions co = CompileOptions(options, sources); - options = co.get_options(compiler); - - if(compiler == "gdc") - { - foreach(ref d; ddocs){d = "-fdoc-inc=" ~ d;} - //or should this only be version(Windows) ? - //TODO: Check in dmd and gdc - foreach(ref l; libs){l = "-L" ~ l;} - } - - //Create modules.ddoc and add it to array of ddocs - if(co.generate_doc) - { - string modules = "MODULES = \n"; - sources.sort; - foreach(src; sources) - { - //get filename - src = split(src, "\\.")[0]; - src = src.replace("/", ".").replace("\\", "."); - modules ~= "\t$(MODULE " ~ src ~ ")\n"; - } - scope(failure){remove("modules.ddoc");} - write("modules.ddoc", modules); - ddocs ~= "modules.ddoc"; - } - - string[] arguments = options ~ sources ~ ddocs ~ libs; - - //Compile - if(compiler == "gdc") - { - //Add support for building libraries to gdc. - //GDC must build incrementally if creating documentation or a lib. - if(co.generate_lib || co.generate_doc || co.no_linking) - { - //Remove options we don't want to pass to gdc when building incrementally. - auto incremental_options = - array(filter!`a != "-lib" && !startsWith(a, "-o")`(options)); - - //Compile files individually, outputting full path names - string[] obj_files; - foreach(source; sources) - { - string obj = source.replace("/", ".")[0 .. $ - 2] ~ ".o"; - string ddoc = obj[0 .. $ - 2]; - if(co.obj_directory !is null) - { - obj = co.obj_directory ~ file_separator ~ obj; - } - obj_files ~= obj; - string[] exec = incremental_options ~ ["-o" ~ obj, "-c"] ~ [source]; - //ensure doc files are always fully qualified. - if(co.generate_doc){exec ~= ddocs ~ ["-fdoc-file=" ~ ddoc ~ ".html"];} - //throws ProcessException on compile failure - execute(compiler, exec); - } - - //use ar to join the .o files into a lib and cleanup obj files - //TODO: how to join on GDC windows? - if(co.generate_lib) - { - //since ar refuses to overwrite it. - remove(co.out_file); - execute("ar", "cq " ~ co.out_file ~ obj_files); - } - - //Remove obj files if -c or -od not were supplied. - if(!co.obj_directory && !co.no_linking) - { - foreach(o; obj_files){remove(o);} - } - } - - if(!co.generate_lib && !co.no_linking) - { - //Remove documentation arguments since they were handled above - execute_compiler(compiler, - array(filter!`!startsWith(a, "-fdoc", "-od")`(arguments))); - } - } - //Compilers other than gdc - else - { - execute_compiler(compiler, arguments); - //Move all html files in doc_path to the doc output folder - //and rename them with the "package.module" naming convention. - if(co.generate_doc) foreach(src; sources) - { - if(src.extension != ".d"){continue;} - - string html = src[0 .. $ - 2] ~ ".html"; - string dest = html.replace("/", ".").replace("\\", "."); - if(co.doc_directory.length > 0) - { - dest = co.doc_directory ~ file_separator ~ dest; - html = co.doc_directory ~ file_separator ~ html; - } - //TODO: Delete remaining folders where source files were placed. - if(html != dest) - { - copy(html, dest); - remove(html); - } - } - } - - //Remove extra files - string basename = split(co.out_file, "/")[$ - 1]; - - if(co.generate_doc){remove("modules.ddoc");} - if(co.out_file && !(co.no_linking || co.obj_directory)) - { - foreach(ext; obj_ext) - { - //Delete object files with same name as output file that dmd sometimes leaves. - try{remove(co.out_file.setExtension(ext));} - catch(FileException e){continue;} - } - } -} - -/** - * Stores compiler options and translates them between compilers. - * - * Also enables -of and -op for easier handling. - */ -struct CompileOptions -{ - public: - ///Do not link. - bool no_linking; - ///Generate documentation. - bool generate_doc; - ///Write documentation to this directory. - string doc_directory; - ///Write documentation to this file. - string doc_file; - ///Generate library rather than object files. - bool generate_lib; - ///Do not write object files. - bool no_objects; - ///write object, library files to this directory. - string obj_directory; - ///Name of output file. - string out_file; - - private: - ///Compiler options. - string[] options_; - - public: - /** - * Construct CompileOptions from command line options. - * - * Params: options = Compiler command line options. - * sources = Source files to compile. - */ - this(string[] options, const string[] sources) - { - foreach(i, opt; options) - { - if(opt == "-c") {no_linking = true;} - else if(["-D", "-fdoc"].canFind(opt)) {generate_doc = true;} - else if(opt.startsWith("-Dd")) {doc_directory = opt[3..$];} - else if(opt.startsWith("-fdoc-dir=")) {doc_directory = opt[10..$];} - else if(opt.startsWith("-Df")) {doc_file = opt[3..$];} - else if(opt.startsWith("-fdoc-file=")) {doc_file = opt[11..$];} - else if(opt == "-lib") {generate_lib = true;} - else if(["-o-", "-fsyntax-only"].canFind(opt)){no_objects = true;} - else if(opt.startsWith("-of")) {out_file = opt[3..$];} - else if(opt.startsWith("-od")) {obj_directory = opt[3..$];} - else if(opt.startsWith("-o") && opt != "-op") {out_file = opt[2..$];} - options_ ~= opt; - } - - //Set the -o (output filename) flag to the first source file if not already set. - //This matches the default behavior of dmd. - string ext = generate_lib ? lib_ext : bin_ext; - if(out_file.length == 0 && !no_linking && !no_objects && sources.length > 0) - { - out_file = sources[0].split("/").back.split("\\.")[0] ~ ext; - options_ ~= "-of" ~ out_file; - } - version (Windows) - { - auto dot = find(out_file, '.'); - auto backslash = retro(find(retro(out_file), '/')); - if(dot <= backslash) - { - out_file ~= bin_ext; - } - } - } - - /** - * Translate DMD compiler options to options of the target compiler. - * - * This function is incomplete. (what about -L? ) - * - * Params: compiler = Compiler to translate to. - * - * Returns: Translated options. - */ - string[] get_options(const string compiler) - { - string[] result = options_.dup; - - if(compiler != "gdc") - { - version(Windows) foreach(ref option; result) - { - option = option.startsWith("-of") ? option.replace("/", "\\") : option; - } - - //ensure ddocs don't overwrite one another. - return result.canFind("-op") ? result : result ~ "-op"; - } - - //is gdc - auto translate = ["-Dd" : "-fdoc-dir=", - "-Df" : "-fdoc-file=", - "-debug=" : "-fdebug=", - "-debug" : "-fdebug", // will this still get selected? - "-inline" : "-finline-functions", - "-L" : "-Wl", - "-lib" : "", - "-O" : "-O3", - "-o-" : "-fsyntax-only", - "-of" : "-o ", - "-unittest" : "-funittest", - "-version" : "-fversion=", - "-version=" : "-fversion=", - "-wi" : "-Wextra", - "-w" : "-Wall", - "-gc" : "-g"]; - - //Perform option translation - foreach(ref option; result) - { - //remove unsupported -od - if(option.startsWith("-od")){option = "";} - if(option == "-D"){option = "-fdoc";} - //Options with a direct translation - else foreach(before, after; translate) - { - if(option.startsWith(before)) - { - option = after ~ option[before.length..$]; - break; - } - } - } - return result; - } - unittest - { - auto sources = ["foo.d"]; - auto options = ["-D", "-inline", "-offoo"]; - auto result = CompileOptions(options, sources).get_options("gdc"); - assert(result[0 .. 3] == ["-fdoc", "-finline-functions", "-o foo"]); - } -} - -///Thrown at errors in execution of other processes (e.g. compiler commands). -class CompileException : Exception -{ - this(const string message, const string file, in size_t line){super(message, file, line);} -}; - -/** - * Wrapper around execute to write compile options to a file to get around max arg lenghts on Windows. - * - * Params: compiler = Compiler to execute. - * arguments = Compiler arguments. - */ -void execute_compiler(const string compiler, string[] arguments) -{ - try - { - version(Windows) - { - write("compile", arguments.join(" ")); - scope(exit){remove("compile");} - execute(compiler ~ " ", ["@compile"]); - } - else{execute(compiler, arguments);} - } - catch(ProcessException e) - { - writeln("Compiler failed: " ~ e.msg); - } -} - -///Thrown at errors in execution of other processes (e.g. compiler commands). -class ProcessException : Exception {this(const string message){super(message);}}; - -/** - * Execute a command-line program and print its output. - * - * Params: command = The command to execute, e.g. "dmd". - * args = Arguments to pass to the command. - * - * Throws: ProcessException on failure or status code 1. - */ -void execute(string command, string[] args) -{ - version(Windows) - { - if(command.startsWith("./")){command = command[2 .. $];} - } - - string full = command ~ " " ~ args.join(" "); - writeln("CDC: " ~ full); - if(int status = system(full ~ "\0") != 0) - { - throw new ProcessException("Process " ~ command ~ " exited with status " ~ - to!string(status)); - } -} - -/** - * Recursively get all files with specified extensions in directory and subdirectories. - * - * Params: directory = Absolute or relative path to the current directory. - * extensions = Extensions to match. - * - * Returns: An array of paths (including filename) relative to directory. - * - * Bugs: LDC fails to return any results. - */ -string[] scan(const string directory, string extensions ...) -{ - string[] result; - foreach(string name; dirEntries(directory, SpanMode.depth)) - { - if(isFile(name) && name.endsWith(extensions)){result ~= name;} - } - return result; -}