Seg fault calling Cygwin from C# - c#

I have some C++ code originally written for Linux that I can build and run without problems under 64-bit Windows using gcc under cygwin. Now, however, I want to turn it into a DLL that I can invoke from a C# program.
I find I can get C# to call C++ functions compiled under cygwin without problems, as long as they don't use any of the standard C/C++ library functions defined in cygwin1.dll. But as soon as I do a printf, for example, the whole thing exits with a "Segmentation fault".
Searching for answers online, I see it claimed that you need to call cygwin_dll_init() first. However, when I add that, it simply terminates with no error message at all!
What am I doing wrong? I'm pretty sure that the .NET runtime is successfully finding both my DLL and cygwin1.dll, because I get a DllNotFoundException instead if either isn't present.
Here's a minimal test case that produces the same symptoms. First, the cygwin/C++ code for the DLL:
#include <cstdio>
extern "C" __declspec(dllexport) int test();
int test() {
printf("Test successful");
return 14;
}
I compile this with "g++ -o test.dll -shared test.cpp".
Here's the C# code that invokes it:
using System;
using System.Runtime.InteropServices;
class MainClass {
[DllImport("cygwin1.dll")]
private static extern void cygwin_dll_init();
[DllImport("test.dll")]
private static extern int test();
public static void Main(string[] args) {
Console.WriteLine("running...");
// Remove this line if you want a seg fault
cygwin_dll_init();
test();
// Seg fault or no, this never gets run
Console.WriteLine("done");
}
}

I strongly recommend that you compile your DLL using the mingw64 cross compiler. This allows you to build an DLLs that does not use the cygwin1.dll. Instead, it will call the Windows runtime DLLs only. As long as you do not need to call any other cygwin DLLs, this should work fine.
you will need to install the mingw64 compiler package using the cygwin setup app. Install the mingw64-x86_64-gcc-g++ package.
create GNUmakefile as follows:
# GNUmakefile - for cygwin make will use this instead of Makefile
CXX=x86_64-w64-mingw32-g++
CXXFLAGS=-Wall -Wextra -Werror
all: libtest.dll
clean:
rm -f *.dll
libtest.dll: test.cpp
$(CXX) $(CXXFLAGS) -shared -o libtest.dll test.cpp
At a cygwin bash prompt, run make clean all
Create Makefile as follows:
# Makefile - for VS nmake
CS=csc
CSFLAGS=-nologo -w:3 -warnaserror+ -optimize- -debug+
all : main.exe
clean :
del /q *.exe 2> nul:
del /q *.pdb 2> nul:
main.exe : main.cs
$(CS) $(CSFLAGS) -t:exe -out:main.exe main.cs
Run this at a cmd.exe prompt as nmake -nologo clean all.
Run the exe as main.exe. As usual libtest.dll must be in the same directory as main.exe, or in the path.
The makefiles here are cut down from versions that build with and without using the cygwin1.dll and, I hope don't, but may contain errors.

Related

How to call cygwin compiled C++ from .NET Core?

I am trying to do something similar to this:
I am working on Windows but my intention is to make my code work on Linux too later on (therefore I work with cygwin and clion for C++ ). VS2017 to compile the C# for a .NET Core app with a normal C# compiler. My problem is getting this error in visual studio:
"The program '[19944] dotnet.exe' has exited with code -1073741819
(0xc0000005) 'Access violation'."
Here is my cmake file (generated with clion):
cmake_minimum_required(VERSION 3.10) project(callFromCsharp)
set(CMAKE_CXX_STANDARD 14)
add_library(callFromCsharp SHARED library.cpp)
Here is my C++ code in library.cpp:
#include <cstdint>
extern "C" __declspec(dllexport) int32_t Test(){
return 10;
}
This is my cmake call generated by clion
C:\Users\Daant.CLion2018.1\system\cygwin_cmake\bin\cmake.exe --build
/cygdrive/c/Users/Daant/CLionProjects/callFromCsharp/cmake-build-release
--target callFromCsharp -- -j 6
Here is my C# code:
class Program
{
[DllImport("cygcallFromCsharp.dll", EntryPoint = "Test", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern Int32 Test();
[STAThread]
static void Main()
{
var res = Test();
Console.WriteLine($"Done! {res}");
Console.ReadLine();
}
}
How to solve this? I just want to call a C++ method without errors or exceptions.
Lets begin with what not to do
when loading Cygwin dll from C# (I guess from Visual studio it will be the same).
do not use AnyCPU as platform, prefer to use x64 or x86 platform, in respectively to the Cygwin dll.
for some reason, I didn't figured out yet why, calling sprintf, sscanf ,stringstream ... and prints to console methods from the dll cause the program to halt.
Now What you can do:
Make sure cygwin bin folder added to path, or copy your DLL's dependencies to the DLL's folder (dependencies are usually: Cygwin1.dll, cyggcc_s-seh-1.dll cygstdc++-6.dll. use Dependency Walker tool to check).
Just to make sure: add EXPORT_API macro, use it on each exported method. like:
#define EXPORT_API extern "C" __cdecl __declspec(dllexport)
Your DLL sample is very simple, compile your code using Cygwin console:
g++ -c library.cpp; g++ -o cygcallFromCsharp.dll library.o
I used from C# the following (debug running dir set to dll location):
DllImport(#"cygcallFromCsharp.dll", CallingConvention=CallingConvention.Cdecl)]
static extern int Test();
Hope it will help.
I implemented a dotnet loader which is compatible with cygwin.
You can find it here: https://github.com/smx-smx/EzDotnet
In order to be able to use Cygwin from .NET (without any crashes) the entry point MUST be a Cygwin application, compiled and linked under cygwin.
I added a cygwin sample that demonstrates the use of P/Invoke as well as read(2) and write(2) to redirect the C# stdin/stdout to cygwin (otherwise it wouldn't be visible)
./samples/cli/ezdotnet.exe ./CoreCLR/cygcoreclrhost.dll ./samples/Managed/Cygwin/bin/Debug/net5.0/Cygwin.dll ManagedSample.EntryPoint Entry

GCC - How to statically link a static mono bundle

I have a .NET application that I want to port to an embedded ARM7 based Linux system. The target is a locked down system running Busybox and I have no write access to the /lib directory (which b.t.w. is empty).I do however have write access to a separate mount point with enough space for my application.
My idea is to compile a static application on a device with the same architecture and copy the binary to the target device. I am using a Beaglebone black for compilation.
How can I compile my .NET application into a 100% statically linked binary?
I am aware of the licensing restrictions of Mono (I have a commercial license).
To keep it simple, my application looks like this.
/// hello.cs
using System;
internal class Program
{
private static void Main()
{
Console.WriteLine("hello");
}
}
Step 1: Compile cs code
$ mcs hello.cs
Step 2: Bundle compiled binary with Mono and output to c code
$ mkbundle -c -o hello.c -oo bundles.o --deps hello.exe --static
OS is: Linux
Note that statically linking the LGPL Mono runtime has more licensing restrictions than
dynamically linking.
See http://www.mono-project.com/Licensing for details on licensing.
Sources: 1 Auto-dependencies: True
embedding: /root/csharp/hello.exe
embedding: /usr/local/lib/mono/4.5/mscorlib.dll
Compiling:
as -o bundles.o temp.s
Step 3: Compile resulting c code
cc -o hello -Wall `pkg-config --cflags mono-2` hello.c bundles.o `pkg-
config --libs-only-L mono-2` -Wl,-Bstatic -lmono-2.0 ./Lib2/libm.a ./Lib2/librt.a ./Lib2/libdl.a
./Lib2/libpthread.a ./Lib2/libgcc.a ./Lib2/libc.a -Wl,-Bdynamic ./Lib2/ld-linux-armhf.so.3
***** Warning message receieved (example):
/media/mono-3.10.0/mono/io-layer/sockets.c:992: warning: Using 'gethostbyname' in statically
linked applications requires at runtime the shared libraries from the glibc version used for
linking
Step 4: Check dependencies
$ ldd hello
/lib/ld-linux-armhf.so.3 (0xb6f92000)
libgcc_s.so.1 => /lib/arm-linux-gnueabihf/libgcc_s.so.1 (0xb6f5e000)
libc.so.6 => /lib/arm-linux-gnueabihf/libc.so.6 (0xb6e7f000)
At this point, the application works on my development system but not on the target system. I am guessing due to missing libraries as the error message I get is File not found.. How can I link the remaining libraries statically?
As an experiment, I've tested a similar approach with a native C application
/// hello.c
#include <stdio.h>
int main()
{
printf("hello\n");
return 0;
}
Step 1: Compile with dynamic links
$ cc hello.c -o hello
Step 2: Check dependencies
$ ldd hello
libc.so.6 => /lib/arm-linux-gnueabihf/libc.so.6 (0xb6e26000)
/lib/ld-linux-armhf.so.3 (0xb6f14000)
As expected, this application does not work on the target system.
Step 3: Compile with static links
$ cc hello.c -o hello -static
Step 4: Check dependencies
$ ldd hello
not a dynamic executable
This application works on my target system.
I am a total newbie on Linux systems in general and have spent many hours trying to find a solution. What worries me a bit is that I'm not even sure if it's solvable :). Any help would be highly appreciated!
Note: If it's impossible to link all libraries statically (for any reason), a solution where these are placed in the same folder as the main application would be totally acceptable. In such a scenario, how would I relink the libraries to ./?

Create C# executable with mkbundle on windows

Im trying to create an executable from a console application.
I have installed mono,cygwin (mingw-gcc, mingw-zlib1, mingw-zlib-devel, pkg-config) and I have added the following lines to my .bashrc file
export PKG_CONFIG_PATH=/cygdrive/c/progra~1/Mono-3.2.3/lib/pkgconfig
export PATH=$PATH:/cygdrive/c/progra~1/Mono-3.2.3/bin
export CC="i686-pc-mingw32-gcc -U _WIN32"
But everytime I try to use mkbundle I receive the following message
Is there a way to make mkbundle work properly on windows.?
(Im using windows 7 x86, mono 3.2.3, the cygwin I found on the official website, xamarin studio 4.2 and net framwork 4)
This problem is still presented in the current mono version under the Windows. This happened because of mono team switched default GC to SGEN. So when you try to use mkbundle as you can see in your error mkbundle utility try to find mono-2 library but this lib didn't included in setup and you have a fail. To solve this you should configure mkbundle to use libmonosgen-2.0 instead of mono-2. Let's try to do this.
The key moment is setting this variable:
export PKG_CONFIG_PATH=/cygdrive/c/progra~1/Mono-3.2.3/lib/pkgconfig
If you go to this directory you will see a lot of *.pc files (package config). This files are responsible for configuration of linking libraries during bundling process. For some reasons mono team hard coded package config file and library to mono-2 (see this line 492). How could we fix it without rebuilding mkbundle? The solution is to use the next bundle script:
# Mono paths
mono_version="3.2.3"
export MONO=/cygdrive/c/progra~2/Mono-$mono_version
machineconfig=$PROGRAMFILES\\Mono-$mono_version\\etc\\mono\\4.5\\machine.config
export PATH=$PATH:$MONO/bin
export PKG_CONFIG_PATH=$MONO/lib/pkgconfig
# Compiller
export CC="i686-pc-mingw32-gcc -U _WIN32"
# Output file name
output_name=Prog.exe
# Produce stub only, do not compile
mkbundle --deps --machine-config "$machineconfig" -c Program.exe
# Produce helper object file. You may see errors at this step but it's a side effect of this method.
mkbundle --deps --machine-config "$machineconfig" -oo temp.o Program.exe
# Compile. Pay attention where I use monosgen-2
i686-pc-mingw32-gcc -U _WIN32 -g -o "$output_name" -Wall temp.c `pkg-config --cflags --libs monosgen-2` temp.o
# Copy libmonosgen-2.dll
cp $MONO/bin/libmonosgen-2.0.dll .
# Run
./$output_name
I had the same problem some time ago and made a script for cygwin. You can try it, would be interesting whether it still works:
mkbunde cygwin script
There are explanations in the script how to setup the environment.
Howto for mkbundle on cygwin + mingw
Here you can find an updated howto make mkbundle work on Windows
First, check your setup:
Install Mono/GTK# in a path that doesn't contains spaces (ie not Program Files then)
Setup a MinGw/Cygwin working compile chain (as the one for
compiling mono on windows).
Define the mandatory environment variables for mkbundle:
mingw compiler location should be in the Windows PATH (used by cmd)
pkg-config should also be in the Windows PATH
Use a cygwin script to defined mono and mingw required variables.
Then you can run:
mkbundle --deps --keeptemp my.exe my.dll -o bundled.exe
Notes:
Copy mono-2.0.dll in the application directory as it should be distributed along the bundled exe
You must specify all exe and dll that are needed for the bundle.
--keeptemp will keep temp.c and temp.s which could come in handy if mkbundle fail on gcc invocation.
If you want to invoke gcc by hand (and it may be needed):
i686-pc-mingw32-gcc -U _WIN32 -g -o output.exe -Wall temp.c $(pkg-config --cflags --libs mono-2) temp.o
Anyone can improve mkbundle
mkbundle is an open sourced C# console application (on mono github)
so it can be easily modified and recompiled depending on your needs.
Reading the code could also be helpful to understand how it works underneath.

How can I resolve 'Metadata foo.dll not found!' errors when compiling C# code on the command line?

On my Windows 7 workstation, I have a variety of compilers installed - including MSVC9 and MSVC10. I recently noticed the following strange problem which only occurs in my MSVC10 environment.
In my MSVC9 shell (I use the one from the start menu), running csc.exe shows that it's using the C# 2008 compiler version 3.5.30729.4926 (.NET 3.5). In the MSVC10 shell, it's compiler version 4.0.30128.1. Now, the following little sample program builds with csc.exe as of MSVC9, but it fails with MSVC10:
using System;
using System.Windows.Automation;
namespace UIAutomationTest
{
class Program
{
static void Main()
{
}
}
}
I use the following command line (with MSVC9 as well as MSVC10) to build the program:
csc Hello.cs /r:UIAutomationClient.dll /nologo
With MSVC9, this succeeds (no output is printed and Hello.exe is built). With MSVC10, the build fails with this error message:
C:\src>csc Hello.cs /r:UIAutomationClient.dll /nologo
error CS0006: Metadata file 'UIAutomationClient.dll' could not be found
Does anybody know why that is?
UPDATE: I noticed that I can make the build work with MSVC10 if I modify the command line so that /r:UIAutomationClient.dll becomes /r:WPF\UIAutomationClient.dll.
Where is this UIAutomationClient.dll file located relative to your cs files?
Try passing the full path of UIAutomationClient.dll.

Compiling/Executing a C# Source File in Command Prompt

How do you compile and execute a .cs file from a command-prompt window?
CSC.exe is the CSharp compiler included in the .NET Framework and can be used to compile from the command prompt. The output can be an executable ".exe", if you use "/target:exe", or a DLL; If you use /target:library, CSC.exe is found in the .NET Framework directory,
e.g. for .NET 3.5, c:\windows\Microsoft.NET\Framework\v3.5\.
To run, first, open a command prompt, click "Start", then type cmd.exe.
You may then have to cd into the directory that holds your source files.
Run the C# compiler like this:
c:\windows\Microsoft.NET\Framework\v3.5\bin\csc.exe
/t:exe /out:MyApplication.exe MyApplication.cs ...
(all on one line)
If you have more than one source module to be compiled, you can put it on that same command line. If you have other assemblies to reference, use /r:AssemblyName.dll .
Ensure you have a static Main() method defined in one of your classes, to act as the "entry point".
To run the resulting EXE, type MyApplication, followed by <ENTER> using the command prompt.
This article on MSDN goes into more detail on the options for the command-line compiler. You can embed resources, set icons, sign assemblies - everything you could do within Visual Studio.
If you have Visual Studio installed, in the "Start menu"; under Visual Studio Tools, you can open a "Visual Studio command prompt", that will set up all required environment and path variables for command line compilation.
While it's very handy to know of this, you should combine it with knowledge of some sort of build tool such as NAnt, MSBuild, FinalBuilder etc. These tools provide a complete build environment, not just the basic compiler.
On a Mac
On a Mac, syntax is similar, only C sharp Compiler is just named csc:
$ csc /target:exe /out:MyApplication.exe MyApplication.cs ...
Then to run it :
$ mono MyApplication.exe
Another way to compile C# programs (without using Visual Studio or without having it installed)
is to create a user variable in environment variables, namely "PATH".
Copy the following path in this variable:
"C:\Windows\Microsoft.NET\Framework\v4.0.30319"
or depending upon which .NET your PC have.
So you don't have to mention the whole path every time you compile a code.
Simply use
"C:\Users\UserName\Desktop>csc [options] filename.cs"
or wherever the path of your code is.
Now you are good to go.
You can compile a C# program :
c: > csc Hello.cs
You can run the program
c: > Hello
For the latest version, first open a Powershell window, go to any folder (e.g. c:\projects\) and run the following
# Get nuget.exe command line
wget https://dist.nuget.org/win-x86-commandline/latest/nuget.exe -OutFile nuget.exe
# Download the C# Roslyn compiler (just a few megs, no need to 'install')
.\nuget.exe install Microsoft.Net.Compilers
# Compiler, meet code
.\Microsoft.Net.Compilers.1.3.2\tools\csc.exe .\HelloWorld.cs
# Run it
.\HelloWorld.exe
An example HelloWorld.cs
using System;
public class HelloWorld {
public static void Main()
{
Console.WriteLine("Hello world!");
}
}
You can also try the new C# interpreter ;)
.\Microsoft.Net.Compilers.1.3.2\tools\csi.exe
> Console.WriteLine("Hello world!");
Hello world!
While it is definitely a good thing knowing how to build at the command line, for most work it might be easier to use an IDE. The C# express edition is free and very good for the money ;-p
Alternatively, things like snippy can be used to run fragments of C# code.
Finally - note that the command line is implementation specific; for MS, it is csc; for mono, it is gmcs and friends.... Likewise, to execute: it is just "exename" for the MS version, but typically "mono exename" for mono.
Finally, many projects are build with build script tools; MSBuild, NAnt, etc.
Here is how to install MSBuild with standalone C# 7.0 compiler which is no longer bundled in the latest .Net Framework 4.7:
Is it possible to install a C# compiler without Visual Studio?
Then just run
"C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\MSBuild\15.0\Bin\Roslyn\csc.exe" MyApplication.cs
to compile single source file to executable.
Also note that .Net Core doesn't support compiling single source file without preconfigured project.
Add to path
C:\Windows\Microsoft.NET\Framework\v3.5
To Compile:
csc file.cs
To Execute:
file
PowerShell can execute C# code out of the box.
One liner to compile & execute a file:
(Add-Type -Path "Program.cs" -PassThru)::Main() #'Main' is the entry point
Supposed you have a .cs file like this:
using System;
public class Program
{
public static void Main()
{
Console.WriteLine("Hello from C#");
}
}
You can build your class files within the VS Command prompt (so that all required environment variables are loaded), not the default Windows command window.
To know more about command line building with csc.exe (the compiler), see this article.
In Windows systems, use the command csc <filname>.cs in the command prompt while the current directory is in Microsoft Visual Studio<Year><Version>
There are two ways:
Using the command prompt:
Start --> Command Prompt
Change the directory to Visual Studio folder, using the command: cd C:\Program Files (x86)\Microsoft Visual Studio\2017\ <Version>
Use the command: csc /.cs
Using Developer Command Prompt :
Start --> Developer Command Prompt for VS 2017
(Here the directory is already set to Visual Studio folder)
Use the command: csc /.cs
Once you write the c# code and save it. You can use the command prompt to execute it just like the other code.
In command prompt you enter the directory your file is in and type
To Compile:
mcs yourfilename.cs
To Execute:
mono yourfilename.exe
if you want your .exe file to be different with a different name, type
To Compile:
mcs yourfilename.cs -out:anyname.exe
To Execute:
mono anyname.exe
This should help!
If you have installed Visual Studio then you have Developer Command Prompt for VS. You can easily build your program using csc command and run your application with the name of the application inside the developer command prompt.
You can open Developer command prompt as given below.
Start => Developer Command Prompt for VS
Hope this helps!
I found a simple way to do this if you have the correct system and environmental variables set up and your path is properly configured.
you just need to run in the directory of the project
dotnet new console --> this will generate the required files such as the .csproj. it will also generate a Program.cs file which it automatically uses as the entry point, if you have other files with your static Main method you can remove this file and it should find the Main entry point automatically.
then all you need to do to run is
dotnet run and it should compile and run automatically
this was how i managed to get my projects working in vs code using gitbash as my terminal. Also I have VS 2019 installed, i used the .net 5.0 framework from this as my system variables. This was the simplest solution i found for basic console programs. It also allows you to add custom imports in your .csproj file
C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\MSBuild\15.0\Bin\Roslyn
this is where you can find the c# compiler that supports c#7 otherwise it will use the .net 4 compilers which supports only c# 5
# File : csharp.ps1
# Purpose : Powershell Script to compile a csharp console application from powershell prompt
try {
# CSharp Compiler
#$csc = "C:\Windows\Microsoft.NET\Framework\v3.5\bin\csc.exe"
$csc = "C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe"
# NOTE: if this path doesn't work search Framework folder for csc.exe
$ErrorActionPreference = 'Stop'
if ($args.Count -eq 0) {
write-host "`nUSAGE: csharp.ps1 (console_application.cs)"
exit 1
}
$file = $args[0];
if (-not(test-path $file)) {
throw "file doesn't exist: $file"
}
$cmd = "$csc /nologo /t:exe /out:${file}.exe $file"
write-host -ForegroundColor Green "`nx: $cmd"
invoke-expression $cmd
}
catch {
write-host -ForegroundColor Red "`nEXCEPTION: $_"
}
finally {
write-host ""
}
// File: helloworld.cs
using System;
namespace MyProgram
{
class Program
{
public static void Main(string[] args)
{
Console.Write("Hello World...");
Console.ReadKey(true);
}
}
}
PS> .\csharp.ps1 helloworld.cs
Search "Path" in windows
Select "Edit the system environment.."
Click on "Environment Variable" right bottom
Double Click on Path in Variable Section
Click on
New and add the path (you Want to add)
Click Okay Okay Okay
for me to run csc from command Prompt
Added this "C:\Windows\Microsoft.NET\Framework\v4.0.30319" to path
then open command prompt where my file is located, and ran this
PS C:\Users\UserName\Downloads\Mouse> csc.exe Mouse.cs
dotnet
This is oooold. But since this is where you end up as a beginner when you ask questions to understand how to use C# like C or C++ in a console using compilers without Visual Studio CE (highly recommended for C# btw if you aren't already using it) you end up getting more confused within the lingo of .NET framework and libraries and SDKs.
If someone like you stumbles upon my answer as a complete beginner:
1. Understand the difference between Framework and SDK.
2. Understand what C# is and what .NET is.
3. THIS: https://dotnet.microsoft.com/learn/dotnet/hello-world-tutorial/intro
You'll pick up the rest along the way.
But instead of using framework I suggest using the SDK and mostly sticking to VS. As for me, I learned C# for unity and mostly game dev.
Also Google is your friend. Ask Questions, stay curious.

Categories