1
Vote

Add support for compiling both native C++ and C++/CLI

description

It won't be possible to use a CodeDomProvider to compile C++/CLI, as we have done for C# and VB. The necessary methods are not yet implemented in the .NET framework's CppCodeProvider class.
 
See this page for instructions on compiling both native C++ and C++/CLI from the command line:
 
http://msdn.microsoft.com/en-us/library/ms235639(VS.80).aspx
 
Since we're going to have to go to the command line for this, we might as well implement support for compiling both unmanaged and managed C++. However, we will start by adding support for C++/CLI.
 
What I propose is this:
 
1) Write the C++/CLI source to a .cpp file.
 
2) Delete the previously existing .exe file, if found.
 
3) Start a process to execute something like the batch file which sets Visual Studio environment variables -- with one additional step to compile the .cpp file. Capture the output from this process, and show it in the output area.
 
4) Test for the existence of the .exe file. If found, start a process to execute it, and capture the console output.
 
Once this has been implemented and tested, we can then add a ComboBox item on MainWindow for native C++. This will be supported in the same way, but the generated C++ source code will not include using statements for .NET namespaces, and the command line statement to compile will differ slightly (see link above).

comments

mfisher_ix wrote Mar 1, 2009 at 3:44 AM

// Here is some C# code which shows how this could be done.

using System;
using System.Diagnostics;
using System.IO;
using System.Text;

namespace ConsoleApplication1
{
class Program
{
    static void Main(string[] args)
    {
        // Should wrap a lot of things here in try-catch...

        // Clear the output folder of temporary files.
        string[] paths = Directory.GetFiles(".", "temp.*");
        foreach (string path in paths)
        {
            File.Delete(path);
        }

        // Write C++ source code to a file.
        string sourceCode = "#include <iostream>\n\nint main()\n{\n\tstd::cout << \"This is a native C++ program.\" << std::endl;\n\treturn 0;\n}";
        //string sourceCode = "int main(){System::Console::WriteLine(\"This is a Visual C++ program.\");}";
        using (FileStream fs = File.Open("temp.cpp", FileMode.OpenOrCreate, FileAccess.Write, FileShare.None))
        {
            Byte[] info = new UTF8Encoding(true).GetBytes(sourceCode);
            fs.Write(info, 0, info.Length);
        }

        // Get a copy of the batch file to set Visual Studio environment variables.
        // This is the batch file for x86. Not going to worry about the others for now.
        string vsvars32 = @"c:\Program Files\Microsoft Visual Studio 9.0\Common7\Tools\vsvars32.bat";
        File.Copy(vsvars32, "temp.bat", true);

        // Append a command to compile the source code file.
        using (FileStream fs = File.Open("temp.bat", FileMode.Append, FileAccess.Write, FileShare.None))
        {
            // We can compile native C++, mixed code, or pure C++/CLI:
            Byte[] info = new UTF8Encoding(true).GetBytes("cl /EHsc temp.cpp");
            //Byte[] info = new UTF8Encoding(true).GetBytes("\ncl /clr temp.cpp");
            //Byte[] info = new UTF8Encoding(true).GetBytes("\ncl /clr:pure temp.cpp");
            fs.Write(info, 0, info.Length);
        }

        // Compile, and capture output.
        using (Process p = new Process())
        {
            p.StartInfo.UseShellExecute = false;
            p.StartInfo.RedirectStandardOutput = true;
            p.StartInfo.FileName = "temp.bat";
            p.Start();
            Console.WriteLine(p.StandardOutput.ReadToEnd());
            p.WaitForExit();
        }

        // Run, and capture output
        if (File.Exists("temp.exe"))
        {
            using (Process p = new Process())
            {
                p.StartInfo.UseShellExecute = false;
                p.StartInfo.RedirectStandardOutput = true;
                p.StartInfo.FileName = "temp.exe";
                p.Start();
                Console.WriteLine(p.StandardOutput.ReadToEnd());
                p.WaitForExit();
            }
        }

        Console.ReadKey();
    }
}
}

wrote Feb 13, 2013 at 1:30 AM