C/C++ Code Compiler in C# - c#

In C#, I am able to compile VB and C# Code, using the code below, but I have no way of compiling C/C++ code. Is there any way of doing this?
C# Compiler:
public void Compile(string ToCompile)
{
string Result = null;
string errors = null;
Microsoft.CSharp.CSharpCodeProvider codeProvider = new Microsoft.CSharp.CSharpCodeProvider();
System.CodeDom.Compiler.ICodeCompiler icc = codeProvider.CreateCompiler();
string Output = #"mypath";
System.CodeDom.Compiler.CompilerParameters parameters = new System.CodeDom.Compiler.CompilerParameters();
parameters.GenerateExecutable = true;
parameters.OutputAssembly = Output;
System.CodeDom.Compiler.CompilerResults results = icc.CompileAssemblyFromSource(parameters, ToCompile);
if (ReturnErrors == true)
{
if (results.Errors.Count > 0)
{
foreach (System.CodeDom.Compiler.CompilerError CompErr in results.Errors)
{
errors +=
"Line number " + CompErr.Line +
", Error Number: " + CompErr.ErrorNumber +
", '" + CompErr.ErrorText + ";" +
Environment.NewLine + Environment.NewLine;
}
Result += "Errors have been found in your code: " + Environment.NewLine + errors;
}
else
{
Result += "Success!";
System.Diagnostics.Process.Start(Output);
}
}
And to create a VB compiler, I simply replace Microsoft.CSharp.CSharpCodeProvider codeProvider = new Microsoft.CSharp.CSharpCodeProvider(); with Microsoft.VisualBasic.VBCodeProvider codeProvider = new Microsoft.VisualBasic.VBCodeProvider();

You can compile c++/cli code, not native c++ as mentioned above.
You can archive c++/cli compilation with CppCodeProvider (http://msdn.microsoft.com/en-us/library/microsoft.visualc.cppcodeprovider(v=vs.85).aspx) class using it like in your example.

I'm assuming you've got a chunk of source, say containing a function with a known prototype, which you want to compile, and run within your currently running application.
In order to do this in native (not managed) C++, you'd need to do the following:
Dynamically store your code into a boilerplate dll source project (i.e. everything written with a gap for the function's code, which you'd insert)
Spawn a C++ compiler (which the end user would have to have pre-installed) to output a dll
Build up a C++/Cli wrapper that wraps the c++ dll that you built above, and compile that too (see Redwan's answer)
Dynamically load your wrapper Dll, and call the function.
If you can work with just managed c++/CLI, then Redwan's answer should be adequate on its own.

Related

How do I call Python scripts with packages from IronPython?

How would I come to implementing a Python script that requires external modules (such as BeautifulSoup4 and requests) in my C# project? I want to call a function in the Python script but it keeps throwing me a "IronPython.Runtime.Exceptions.ImportException: 'No module named requests'".
I do not have any IronPython script written because I'm using a Python script that was made from another user. I have a virtual environment set up with Python to import the necessary modules.
I have no idea where to approach this. I've looked on multiple sites but they all require me to write an IronPython script. Are there no other options to calling functions other than setting up the necessary script?
C# Code:
static dynamic pythonFile;
static void Main(string[] args)
{
// Loading Python file
var ipy = Python.CreateRuntime();
pythonFile = ipy.UseFile("test.py"); //throws error when this launches.
DisplayMain();
Console.ReadKey();
}
Python Code (small snippet for example):
import requests
def get_stock(stock_name, price_metric):
print(stock_name + " " + price_metric)
def get_industry_indicators(startTime, endTime):
print(startTime + " " + endTime)
def get_market_cap(industry, startTime, endTime):
print(industry + " " + startTime + " " + endTime)
def get_headers(link):
print(requests.get(link))
I want to be able to call my python function (get_headers) and pass in a link and then have it print on my C# Console. Please help!
I found the error. Search paths for the needed modules must be included. Here is an example.
var engine = Python.CreateEngine();
var searchPaths = new List<string>();
searchPaths.Add(AppDomain.CurrentDomain.BaseDirectory + #"\Lib\site-packages");
searchPaths.Add(#"C:\...\projectName\Lib\");
engine.SetSearchPaths(searchPaths);
engine.ExecuteFile("test.py");

How does one run code within the browser at Run-time

I have been using the documentation here https://support.microsoft.com/en-gb/help/304655/how-to-programmatically-compile-code-using-c-compiler
I am trying to learn about compilers a bit more I want to host on my own site a simple text editor that I can use to run the code of a script say something simple like
The program is required to Print out Console.WriteLine("Hello World");
If anything other than Hello World is printed out the program would be in error.
I have been looking at Microsoft code on running .net code at runtime but both these force it to create an exe I want the result to be like .net fiddle in a text box.
I presume what I have to do some how is run the exe and use the process to return the result bare in mind this is inside a mvc applicaiton.
Or is their any cool nugets that can save me the time here.
private void Compiler(string code)
{
CSharpCodeProvider codeProvider = new CSharpCodeProvider();
ICodeCompiler icc = codeProvider.CreateCompiler();
string Output = "Out.exe";
System.CodeDom.Compiler.CompilerParameters parameters = new
CompilerParameters();
//Make sure we generate an EXE, not a DLL
parameters.GenerateExecutable = true;
parameters.OutputAssembly = Output;
CompilerResults results = icc.CompileAssemblyFromSource(parameters, code);
if (results.Errors.Count > 0)
{
foreach (CompilerError CompErr in results.Errors)
{
CompilerError error = new CompilerError();
error.Line = CompErr.Line;
error.ErrorNumber = CompErr.ErrorNumber;
error.ErrorText = CompErr.ErrorText;
}
}
else
{
//Successful Compile
CodeResult result = new CodeResult();
result.Message = "Success";
}
}
So how would one capture the above and return and also how does one add support for other languages like python or vb.net
Is this something that blazor could perhaps be good at doing for me ?
I am wanting to provide an experience like .net fiddle https://dotnetfiddle.net
Suchiman / Robin Sue is has integrated the Monaco editor as well as an in-browser C# compiler in this nifty blazor project (live demo)

C# When adding a referenced assembly it is throwing a file not found error

I have a program that dynamically runs user entered C# code, that part works fine and the results are outputted to a location given by the user (or a system default).
My users are asking that I output the results to an "output window" so they can view the results without having to go to file.
I am trying to reference the program the dynamically created C# code is being generated in so I can output the results, but I am getting a file not found error when trying to add the reference for the program that it is being run in.
Here is my code:
private static Assembly CompileSourceCodeDom(string sourceCode)
{
CodeDomProvider cpd = new CSharpCodeProvider();
var cp = new CompilerParameters();
LogConsoleMessage(Assembly.GetExecutingAssembly().CodeBase + "\n");
cp.ReferencedAssemblies.Add(Assembly.GetExecutingAssembly().CodeBase);
cp.ReferencedAssemblies.Add("System.dll");
cp.ReferencedAssemblies.Add("System.Windows.Forms.dll");
cp.ReferencedAssemblies.Add("System.Core.dll");
cp.GenerateExecutable = false;
CompilerResults cr = cpd.CompileAssemblyFromSource(cp, sourceCode);
cr.Errors.Cast<CompilerError>().ToList().ForEach(error =>
LogConsoleMessage(error.ErrorText + " Line #: " + error.Line + " Column:
" + error.Column + "\n"));
if (cr.Errors.Count == 0)
{
return cr.CompiledAssembly;
}
else
{
return null;
}
}
This is the line where the error is being displayed
cr.Errors.Cast<ComplierErrors>().ToList().ForEach(error =>
LogConsoleMessage(error.ErrorText + " Line #: " + error.Line + " Column:
" + error.Column + "\n")); is where the error message is coming out
Here is the exact error message. I checked the folder and it does exists.
Metadata file 'file:///C:/Users/[my user]/source/repos/test/test/bin/Debug/test.exe' could not be found Line #: 0 Column: 0
Does this have to do with the fact that the program is currently running? Because I cannot seem to find a way to reference this code. Does anyone have any suggestions about a different way to output the results to a visible location?
Thanks in advance!
EDIT
Assembly.GetExecutingAssembly().CodeBase
was changed to
Assembly.GetExecutingAssembly().Location
Assembly.CodeBase returns the assembly location formatted as an URI like file://... which the compiler is apparently not able to parse.
Instead, try using the "pure" local or UNC path of your assembly. To get the local or UNC path of the assembly, replace CodeBase with the Location property:
LogConsoleMessage(Assembly.GetExecutingAssembly().Location + "\n");
cp.ReferencedAssemblies.Add(Assembly.GetExecutingAssembly().Location);

Runtime C# Compile All Files in a Folder from Code

I am successfully doing run-time compilation using the code below. Except that when the number of input *.cs files is large I get the following error.
System.SystemException: Error running mono.exe: The filename or extension is too long.
I believe this is due to the command line length limit as in this article.
Here is the code
var codeProvider = new CSharpCodeProvider (
new Dictionary<string, string> { { "CompilerVersion", "v4.0" } });
string EngineOutput = Path.GetFileName(dir) + ".dll";
parameters.GenerateExecutable = false;
parameters.OutputAssembly = EngineOutput;
CompilerResults results = codeProvider.CompileAssemblyFromFile (parameters, engineFiles.ToArray ());
Since all source files are in one folder, if there is a way to pass that folder using the -recurse programmatically will be great. Or if there were a method that takes a folder like codeProvider.CompileAssemblyFromDirectoryRecursive that would have also been great, but to my knowledge that doesn't exist.
I tried the following, but it didn't work. The compiler only picks the fake.cs and not the folder specified by /recurse.
parameters.CompilerOptions += " /recurse:" + dir + System.IO.Path.PathSeparator + "*.cs";
results = codeProvider.CompileAssemblyFromFile (parameters, new string[1] { "fake.cs" });
Thanks for advance.
I just replaced the PathSeparator with DirectorySeparator, then it works.
parameters.CompilerOptions += " /recurse:" + dir + System.IO.Path.DirectorySeparatorChar + "*.cs";

Statically linking Mono using mkbundle in Windows

I'm having trouble statically linking Mono using mkbundle in Windows. In my attempts to figure out what's going on I hit a wall. When you pass the static flag to mkbundle in windows it looks for the file monosgen-2.0-static.lib in the mono directory. This directory is defined by the line the below:
string monoPath = GetEnv("MONOPREFIX", #"C:\Program Files (x86)\Mono");
The contents of this directory after installing mono 5.1.1 is:
First I noticed the file naming convention is different from that that mkbundle is looking for (monosgen-2.0 should be mono-2.0-sgen). I can change this just fine, however I suspect - given the file name - that the mono-2.0-sgen.lib file shown in the screenshot isn't statically compiled, as when I try to run my bundled application it first can't find the sgen dll, and then when it can it can't find others.
At this point I'm wondering if mkbundle officially works on Windows, and if it does am I doing something fundamentally wrong? I have seen older post asking for help setting mkbundle in Windows and have posted questions regarding this myself. Most point to using mingw instead of cl.exe. Should I be using this instead?
The source for this snippet is shown below. You can find the entire source code here https://github.com/mono/mono/blob/master/mcs/tools/mkbundle/mkbundle.cs.
if (style == "windows")
{
Func<string, string> quote = (pp) => { return "\"" + pp + "\""; };
string compiler = GetEnv("CC", "cl.exe");
string winsdkPath = GetEnv("WINSDK", #"C:\Program Files (x86)\Windows Kits\8.1");
string vsPath = GetEnv("VSINCLUDE", #"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC");
string monoPath = GetEnv("MONOPREFIX", #"C:\Program Files (x86)\Mono");
string[] includes = new string[] {winsdkPath + #"\Include\um", winsdkPath + #"\Include\shared", vsPath + #"\include", monoPath + #"\include\mono-2.0", "." };
// string[] libs = new string[] { winsdkPath + #"\Lib\winv6.3\um\x86" , vsPath + #"\lib" };
var linkLibraries = new string[] { "kernel32.lib",
"version.lib",
"Ws2_32.lib",
"Mswsock.lib",
"Psapi.lib",
"shell32.lib",
"OleAut32.lib",
"ole32.lib",
"winmm.lib",
"user32.lib",
"libvcruntime.lib",
"advapi32.lib",
"OLDNAMES.lib",
"libucrt.lib" };
string glue_obj = "mkbundle_glue.obj";
string monoLib;
if (static_link)
monoLib = LocateFile (monoPath + #"\lib\monosgen-2.0-static.lib");
else {
Console.WriteLine ("WARNING: Dynamically linking the Mono runtime on Windows is not a tested option.");
monoLib = LocateFile (monoPath + #"\lib\monosgen-2.0.lib");
LocateFile (monoPath + #"\lib\monosgen-2.0.dll"); // in this case, the .lib is just the import library, and the .dll is also needed
}
var compilerArgs = new List<string>();
compilerArgs.Add("/MT");
foreach (string include in includes)
compilerArgs.Add(String.Format ("/I {0}", quote (include)));
if (!nomain || custom_main != null) {
compilerArgs.Add(quote(temp_c));
compilerArgs.Add(quote(temp_o));
if (custom_main != null)
compilerArgs.Add(quote(custom_main));
compilerArgs.Add(quote(monoLib));
compilerArgs.Add("/link");
compilerArgs.Add("/NODEFAULTLIB");
compilerArgs.Add("/SUBSYSTEM:windows");
compilerArgs.Add("/ENTRY:mainCRTStartup");
compilerArgs.AddRange(linkLibraries);
compilerArgs.Add("/out:"+ output);
string cl_cmd = String.Format("{0} {1}", compiler, String.Join(" ", compilerArgs.ToArray()));
Execute (cl_cmd);
}

Categories

Resources