示例#1
0
        public void GenerateCode()
        {
            if (CSharpToD.log)
            {
                this.log = new BufferedNativeFileSink(NativeFile.Open(
                                                          Path.Combine(CSharpToD.logDirectory, projectModels.outputName),
                                                          FileMode.Create, FileAccess.Write, FileShare.ReadWrite), new byte[256]);
            }

            // Determine File Name
            String projectSourceDirectory;

            if (namespaceTree.subnodes.Count == 0)
            {
                projectSourceDirectory = null;
                this.filenameFullPath  = Path.Combine(CSharpToD.generatedCodePath, projectModels.outputName + ".d");
            }
            else
            {
                projectSourceDirectory = Path.Combine(CSharpToD.generatedCodePath,
                                                      projectModels.outputName);
                this.filenameFullPath = Path.Combine(projectSourceDirectory, "package.d");
            }

            ProjectFirstPassVisitor firstPass;

            SynchronizedDirectoryCreator.Create(Path.GetDirectoryName(filenameFullPath));
            Console.WriteLine("Creating D Source File '{0}'...", filenameFullPath);
            using (DlangWriter writer = new DlangWriter(new BufferedNativeFileSink(
                                                            NativeFile.Open(filenameFullPath, FileMode.Create, FileAccess.Write, FileShare.ReadWrite), new byte[512])))
            {
                writer.WriteLine("module {0};", projectModels.outputName);
                writer.WriteLine();

                //
                // First Pass: find imports
                //
                firstPass = new ProjectFirstPassVisitor(writer, log);
                this.namespaceTree.FirstPassVisit(firstPass);

                //
                // Write Imports
                //
                foreach (KeyValuePair <String, HashSet <TypeSymbolAndArity> > namespaceAndTypes in firstPass.typeSymbolsByNamespace)
                {
                    String @namespace = namespaceAndTypes.Key;
                    if (@namespace.Length > 0)
                    {
                        writer.WriteLine("import {0}.{1} :", projectModels.outputName, @namespace);
                        writer.Tab();
                        uint typeIndex = 0;
                        uint lastIndex = (uint)namespaceAndTypes.Value.Count - 1;
                        foreach (TypeSymbolAndArity typeSymbol in namespaceAndTypes.Value)
                        {
                            writer.Write(typeSymbol.name);
                            if (typeSymbol.arity > 0)
                            {
                                writer.Write("{0}", typeSymbol.arity);
                            }
                            if (typeIndex < lastIndex)
                            {
                                writer.WriteLine(",");
                            }
                            else
                            {
                                writer.WriteLine(";");
                            }
                            typeIndex++;
                        }
                        writer.Untab();
                    }
                }

                //
                // Generate Code
                //
                {
                    var generator = new ProjectVisitorGenerator(this, writer, firstPass);
                    this.namespaceTree.GenerateCode(writer, generator);
                }
            }

            //
            // Generate Namespace Alias Files
            //
            foreach (KeyValuePair <String, HashSet <TypeSymbolAndArity> > namespaceAndTypes in firstPass.typeSymbolsByNamespace)
            {
                String @namespace = namespaceAndTypes.Key;
                if (@namespace.Length > 0)
                {
                    //
                    // Determine Namespace Alias Filename
                    //
                    String namespaceAliasFilename;
                    {
                        Boolean namespaceHasChildNamespaces = false;
                        foreach (string otherNamespace in firstPass.typeSymbolsByNamespace.Keys)
                        {
                            if (otherNamespace.Length > @namespace.Length &&
                                otherNamespace.StartsWith(@namespace))
                            {
                                namespaceHasChildNamespaces = true;
                                break;
                            }
                        }

                        String filenameRelative;
                        if (namespaceHasChildNamespaces)
                        {
                            filenameRelative = Path.Combine(
                                @namespace.Replace('.', Path.DirectorySeparatorChar), "package.d");
                        }
                        else
                        {
                            int lastDotIndex = @namespace.LastIndexOf('.');
                            if (lastDotIndex < 0)
                            {
                                filenameRelative = @namespace + ".d";
                            }
                            else
                            {
                                filenameRelative = Path.Combine(
                                    @namespace.Remove(lastDotIndex).Replace('.', Path.DirectorySeparatorChar),
                                    @namespace.Substring(lastDotIndex + 1) + ".d");
                            }
                        }
                        namespaceAliasFilename = Path.Combine(projectSourceDirectory, filenameRelative);
                        namespaceFiles.Add(namespaceAliasFilename);
                        //Console.WriteLine("[DEBUG] Namespace '{0}' going to file '{1}'", @namespace, filenameFullPath);
                    }

                    SynchronizedDirectoryCreator.Create(Path.GetDirectoryName(namespaceAliasFilename));
                    Console.WriteLine("Creating D Source File '{0}'...", namespaceAliasFilename);
                    using (DlangWriter writer = new DlangWriter(new BufferedNativeFileSink(
                                                                    NativeFile.Open(namespaceAliasFilename, FileMode.Create, FileAccess.Write, FileShare.ReadWrite), new byte[512])))
                    {
                        writer.WriteLine("module {0}.{1};", projectModels.outputName, @namespace);
                        writer.WriteLine();
                        writer.WriteLine("static import {0};", projectModels.outputName);
                        writer.WriteLine();
                        foreach (TypeSymbolAndArity typeSymbol in namespaceAndTypes.Value)
                        {
                            if (typeSymbol.arity > 0)
                            {
                                writer.WriteLine("alias {0}{1} = {2}.{3}.{0}{1};",
                                                 typeSymbol.name, typeSymbol.arity, projectModels.outputName, @namespace);
                            }
                            else
                            {
                                writer.WriteLine("alias {0} = {1}.{2}.{0};",
                                                 typeSymbol.name, projectModels.outputName, @namespace);
                            }
                        }
                    }
                }
            }
        }
        public static void MakeDProjectFile(Config config, ProjectModels[] projectModelsArray)
        {
            String projectFile = Path.Combine(CSharpToD.generatedCodePath, "build.d");

            using (DlangWriter writer = new DlangWriter(new BufferedNativeFileSink(
                                                            NativeFile.Open(projectFile, FileMode.Create, FileAccess.Write, FileShare.ReadWrite), new byte[512])))
            {
                writer.WriteLine(@"import std.stdio;
import std.getopt  : getopt;
import std.format  : format;
import std.process : spawnShell, wait;
import std.path    : setExtension, buildNormalizedPath;

enum OutputType {Library,Exe}
struct Project
{
    string outputName;
    OutputType outputType;
    string[] sourceFiles;
}
");

                writer.WriteLine(@"immutable string rootPath = `{0}`;", CSharpToD.generatedCodePath);

                writer.WriteLine(@"immutable string mscorlibPath = `{0}`;", CSharpToD.mscorlibPath);
                writer.WriteLine(@"enum DEFAULT_NO_MSCORLIB = {0};", config.noMscorlib ? "true" : "false");

                writer.WriteLine(@"immutable string[] includePaths = [");
                writer.Tab();
                foreach (String includePath in config.includePaths)
                {
                    writer.WriteLine("`{0}`,", Path.Combine(CSharpToD.conversionRoot, includePath));
                }
                writer.Untab();
                writer.WriteLine("];");

                writer.WriteLine(@"immutable string[] libraries = [");
                writer.Tab();
                foreach (String library in config.libraries)
                {
                    writer.WriteLine("`{0}`,", Path.Combine(CSharpToD.conversionRoot, library));
                }
                writer.Untab();
                writer.WriteLine("];");

                {
                    writer.WriteLine(@"immutable Project[] projects = [");
                    writer.Tab();
                    foreach (ProjectModels project in projectModelsArray)
                    {
                        writer.WriteLine("immutable Project(\"{0}\", OutputType.{1}, [",
                                         project.assemblyPackageName, project.outputType);
                        writer.Tab();

                        DlangGenerator[] generators = System.Linq.Enumerable.ToArray(project.namespaceGeneratorMap.Values);
                        // Sort so that the source files are always in the same order
                        // no matter the timing
                        Array.Sort(generators);
                        foreach (DlangGenerator generator in generators)
                        {
                            // TODO: make these files relative
                            writer.WriteLine("`{0}`,", generator.filenameFullPath);
                        }
                        writer.Untab();
                        writer.WriteLine("]),");
                    }
                    writer.Untab();
                    writer.WriteLine("];");
                }

                writer.WriteLine(@"
int tryRun(string command)
{
    writefln(""[RUN] '%s'"", command);
    auto pid = spawnShell(command);
    return wait(pid);
}
void run(string command)
{
    auto exitCode = tryRun(command);
    if(exitCode) {
        writefln(""Error: last [RUN] command failed (exit code %s)"", exitCode);
    }
}
int main(string[] args)
{
    bool noMscorlib = DEFAULT_NO_MSCORLIB;
    bool compileSingleFiles = false;
    getopt(args,
        ""no-mscorlib"", &noMscorlib,
        ""compile-single-files"", &compileSingleFiles);

    foreach(project; projects)
    {
        writefln(""Building project '%s'..."", project.outputName);

        string[] objectFiles = new string[project.sourceFiles.length];
        foreach(i, sourceFile; project.sourceFiles) {
            objectFiles[i] = sourceFile.setExtension(""obj"");
        }

        string compileCommand = format(""dmd -I%s"", rootPath);
        if(!noMscorlib) {
            compileCommand ~= "" -I"" ~ mscorlibPath;
        }
        foreach(includePath; includePaths) {
            compileCommand ~= "" -I"" ~ buildNormalizedPath(includePath);
        }

        string linkArguments = """";
        if(project.outputType == OutputType.Library) {
            linkArguments ~= "" -lib"";
        }
        if(!noMscorlib) {
            linkArguments ~= "" "" ~ buildNormalizedPath(mscorlibPath, ""mscorlib.lib"");
        }
        foreach(library; libraries) {
            linkArguments ~= format("" %s"", library);
        }
        linkArguments ~= format("" -of%s"", buildNormalizedPath(rootPath, project.outputName));

        // The compileSingleFiles option is MUCH slower, but I'm keeping it for now
        // because compiling all source files together could cause a machine to run out of memory
        if(compileSingleFiles)
        {
            // Compile
            foreach(i, sourceFile; project.sourceFiles) {
                if(tryRun(format(""%s -c -of%s %s"", compileCommand, objectFiles[i], sourceFile))) {
                    return 1;
                }
            }

            // Link
            string linkCommand = ""dmd""~linkArguments;
            foreach(objectFile; objectFiles) {
                linkCommand ~= format("" %s"", objectFile);
            }
            if(tryRun(linkCommand)) {
                return 1;
            }
        } else {
            string compileAndLinkCommand = compileCommand~linkArguments;
            foreach(i, sourceFile; project.sourceFiles) {
                compileAndLinkCommand ~= "" ""~sourceFile;
            }
            if(tryRun(compileAndLinkCommand)) {
                return 1;
            }
        }
    }
    writeln(""Success"");
    return 0;
}
");
            }
        }