How to convert C uint64_t to Cgo consistently across OS? - c

I am using some C library form Go, using cgo to handle the conversion.
I have a C header file that looks like:
#include <stdlib.h>
typedef struct {
k uint64_t;
} params;
This structure is used from Go with code like:
package test
/*
#cgo CFLAGS: -g -Wall
#cgo LDFLAGS: -L. -lmylib -lm -ldl
#include "mylib.h"
*/
import "C"
func NewParams(k uint64) Paramets {
return Params{
k: C.ulonglong(k),
}
}
The code compiles fine on OS X with Apple clang version 12.0.0, but fails on Linux with clang version 7.1.0, yielding the following error:
cannot use _Ctype_ulonglong(k) (type _Ctype_ulonglong) as type _Ctype_ulong in field value
If I change the call to C.ulonglong to C.ulong, it works fine on linux but then fails on OS X.
How can I ensure the same code works on both platform?

Using go build -work I was able to confirm the issue stems from differences in mapping:
On the linux side, a C unit64_t gets mapped to a C.ulong
On the Mac side, it gets mapped to C.ulonglong
Note that both C.ulong and C.ulonglong gets mapped to a go uint64 but using the Go type directly and removing the C.xxx(k) conversion fails.
Solution is to use C.uint64_t(k) which makes it explicit the size of the type we are talking about. This is just fine because the C type is uin64_t anyways.

Related

Compiling against 64bits DLL cause segfault but works in 32bits

Context
On Windows, using mingw32 and its x86_64 version. In order to use a third-party library (within Unity), I'am trying to build a wrapper library (dll) around the native one (to simplify the integration in Unity). I need this library to be 64bits.
The problem arises when linking against the created wrapper library in a test program: the program crash on a segfault, whereas the 32bits version runs just fine.
Procedure
I am using the 32 and 64bits version of the dll provided by the third-party (see Dependencies analysis on Picture) to compile wrapping libraries.
The wrapper library is simply wrapping some functions of the native library. The header is:
#include <stdlib.h>
#include <stdio.h>
#include "ATC3DG.h"
#pragma once
#ifdef __cplusplus
extern "C"
{
#endif
__declspec(dllexport) int trakSTAR_Init();
__declspec(dllexport) int trakSTAR_GetMeasurement(double S1_X[3], double S1_A[3], double *S1_T, unsigned short * S1_Q, double S2_X[3], double S2_A[3], double *S2_T, unsigned short * S2_Q, double S3_X[3], double S3_A[3], double *S3_T, unsigned short * S3_Q);
__declspec(dllexport) int trakSTAR_Close();
__declspec(dllexport) void trakSTAR_ErrorName(int errorcode, char *errortxt);
#ifdef __cplusplus
}
#endif
It is compiling fine for both the 32 and 64bits versions respectively with:
mingw32-gcc.exe -shared -Iinclude -o bin\Release\libWrapper.dll WrapperLib.c lib\win32\nativelib.lib
and
x86_64-w64-mingw32-gcc.exe -shared -Iinclude -o bin\Release\libWrapper64.dll WrapperLib.c lib\win64\nativelib64.lib
Then, compiling test codes linking this Wrapper dll using respectively:
mingw32-gcc.exe -I.\include -L.\test -llibWrapper .\test\MainTest.c -o test\Test32
and
x86_64-w64-mingw32-gcc.exe -g -I.\include -L.\test .\test\MainTest.c -o test\Test64 -llibWrapper64
also works fine and produce the two executables.
Problem
Now, while the 32bits version (Test32.exe) runs fine, the 64bits version produce a Segfault straight ahead (no even first console print). The necessary dll (native and wrapper for both 32 and 64bits version are in the execution folder).
When inspecting the two Wrapper dlls with Dependencies, I can't see any major difference (see picture).
What could be the cause of the problem with the 64bits library?
What are my options to understand what is going wrong and debug/inspect further?
Note: Compiling a test code against the native dll works fine for both in 32 and 64 bits.
Note2: Running GDB on the faulty test program does not provide more information.

Compilation fails with #include "..." but not with #include <...>

I'm currently toying around with the C library NanoVG library. The library depends on OpenGL fucntions and has 2 header files nanovg.h and nanovg_gl.h. The latter file contains part of the implementation. For convenience, I have placed these two header files in /usr/include/nanovg.
When I try to compile the following code to an object file, gcc does not complain:
// working.c
#include <GL/gl.h>
#include <nanovg/nanovg.h>
#define NANOVG_GL3_IMPLEMENTATION
#include <nanovg/nanovg_gl.h>
(Command: gcc -c working.c -o working.o)
Now, I copy the header files from /usr/include/nanovg/ to the working directory, and replace the code with:
// notworking.c
#include <GL/gl.h>
#include "nanovg.h"
#define NANOVG_GL3_IMPLEMENTATION
#include "nanovg_gl.h"
(Command: gcc -c notworking.c -o notworking.o)
Gcc now complains that some OpenGL functions are not declared:
... (many more similar complaints)
src/nanovg_gl.h: In function ‘glnvg__renderDelete’:
src/nanovg_gl.h:1540:3: warning: implicit declaration of function ‘glDeleteBuffers’; did you mean ‘glSelectBuffer’? [-Wimplicit-function-declaration]
1540 | glDeleteBuffers(1, &gl->fragBuf);
| ^~~~~~~~~~~~~~~
...
Why does one file compile smoothly but not the other?
A bit deeper:
Using the cpp tool, I found that the difference between the two pre-processed files is limited to # directives but I don't see any difference as far as the "C content" goes. Below is a snippet of the pre-processed working.c. If I add the # lines from the pre-processed notworking.c, then gcc no longer compiles the pre-processed working.c and complains about a missing declaration for glDeleteBuffers.
// ...
if (gl ==
// # 1533 "src/nanovg_gl.h" 3 4 // <- uncomment this line and glDeleteBuffers is considered missing by gcc
((void *)0)
// # 1533 "src/nanovg_gl.h" // <- idem
) return;
glnvg__deleteShader(&gl->shader);
if (gl->fragBuf != 0)
glDeleteBuffers(1, &gl->fragBuf); // <- the function that gcc complains about is here
// ...
Edit: Just to make sure that I did not do anything sneaky that might have caused the difference, I followed the following steps which hopefully should be reproducible on another computer:
GCC version: gcc (Ubuntu 10.3.0-1ubuntu1) 10.3.0
Copy the version of GL/gl.h can be found here to working directory and call it glfoo.h
Copy the headers of nanovg (as found in the repo) to /usr/include/nanovg/ and nanovg/ (relative to working directory).
Save the following as test.c in the working dir:
#include "glfoo.h"
#include <nanovg/nanovg.h>
#define NANOVG_GL3_IMPLEMENTATION
#include <nanovg/nanovg_gl.h>
Run gcc -c test.c -o test.o => compilation works
Replace <...> with ".." on lines 2 and 4 and run command => compilation fails.
Just tried these exact steps and I was able to reproduce it.
After investigating this a bit I found the solution. gcc does not apply the same warning level to system headers as it does for "normal" files (this is mainly because system headers are sometimes doing weird things which are not backed up by the C standard, but are "safe" for the platform they are coming with).
The gcc documentation states (emphasis mine):
-Wsystem-headers:
Print warning messages for constructs found in system header files. Warnings from system headers are normally suppressed, on
the assumption that they usually do not indicate real problems and
would only make the compiler output harder to read. Using this
command-line option tells GCC to emit warnings from system headers as
if they occurred in user code. However, note that using -Wall in
conjunction with this option does not warn about unknown pragmas in
system headers—for that, -Wunknown-pragmas must also be used.
When you include nanovg via <...>, it is treated as a system header.
So doing gcc -Wsystem-headers working.c actually will bring on the warning.
Note that your code is neither working in working.c nor notworking.c, as working.c just hides the warning messages. The proper way to access any GL function beyond what is defined in GL 1.1 is to use the GL extension mechanism, which means you have to query the GL function pointers at run-time. Full GL loader libs like GLEW and glad can do that for you automatically. Many of these loaders (including GLEW and GLAD) work by re-#define-ing every GL function name to an internal function pointer, so when you include the header which comes with the loader, every GL function called in your code (and nanovg's) will be re-routed to the loader-libraries function pointers, and your code can actually work (provided you properly initialize the loader at run-time before any of the GL functions is called).
simply
#include <file.h>
include file from the path listed default to the compiler, while
#include "file.h"
include file from the current folder (where you are compiling).
As in your case , switching from <> to "" makes come files missing which makes that compiler error coming.

Using Libdl.dlopen kills Julia

I am trying to call a C code from Julia v0.6.2, Windows 10.
Here is the C code I compiled into a DLL with Cygwin gcc.
int timesTwo(int x) {
return 2*x;
}
The compile commands:
gcc -c mydll.c
gcc -shared -o mydll.dll mydll.o
I tested the DLL with a test C program and it works. Then I tried to call it with Julia using an absolute path to the DLL.
using Base.Libdl
x = Int32(2)
mylib = dlopen("C:\\Users\\pedro\\Documents\\codigos\\exampleDLL\\C\\mydll.dll")
ccall((:timesTwo, mylib), Int32, (Int32,), x)
Then the Julia's Workspace is restarted (all variables become undefined as soon as I use the command dlopen).
What is happening and how can I solve it?
Update
That must be a windows issue. Could not reproduce in an Ubuntu distro.
I would try to use the same compiler that Julia uses (with the -fPIC flag) to build your DLL. On Windows, julia is actually build with the
Cygwin-to-MinGW cross-compiler:
https://github.com/JuliaLang/julia/blob/master/README.windows.md#cygwin-to-mingw-cross-compiling
Can you install the mingw64-x86_64-gcc-core package (for just the C compiler) and use the x86_64-w64-mingw32-gcc compiler command (instead of gcc) ?
Use the -fPIC switch to generate the position independent code. Plus, you might be lying to Julia unless your int is defined as int32 on the specific platform. To be sure, you need to change ccall((:timesTwo, mylib), Int32, (Int32,), x) to ccall((:timesTwo, mylib), Cint, (Cint,), x). Finally, to make the code work for any operating system, please consider replacing mylib = dlopen("C:\\Users\\pedro\\Documents\\codigos\\exampleDLL\\C\\mydll.dll") to const mylib = dlopen(joinpath(pwd(), "mydll.dll")). const is there for efficiency reasons, joinpath is OS-agnostic, meaning that it will add forward slash for *nix-based systems. Later on, when you want to change the library to .so, for instance, you should not deal with slashes, too.

Using Go code in an existing C project

Ever since Go 1.5 came out, I started taking another look at how I could integrate it into an existing project of mine.
The project's codebase is written entirely in C for low level access to to hardware and other fun stuff. However, some of the higher level things are tedious, and I would like to start writing them in a higher level language (Go)
Is there any way I can call Go code from a C program? I installed Go 1.5, which added -buildmode=c-archive (https://golang.org/s/execmodes) which I am trying to get working.
However, I can't seem to get Go to generate the appropriate header files to allow my project to actually compile. When I generate the archive, I see the function in the exported symbols (using objdump), but without the header files to include gcc complains about the function not existing (as expected)
I'm quite new to Go - however, I love the language and would like to make use of it. Is there any idiomatic way ("idiomatic" gets used a lot in the world of Go I see...) to get this to play nicely with each other?
The reason I asked this question and specifically mentioned Go 1.5 is that according to this document, https://docs.google.com/document/d/1nr-TQHw_er6GOQRsF6T43GGhFDelrAP0NqSS_00RgZQ/edit?pli=1#heading=h.1gw5ytjfcoke
Go 1.5 added support for non-Go programs to call Go code. Specifically, mentioned under the section "Go code linked into, and called from, a non-Go program"
To build an archive callable from C, you will need to mark them as exported CGo symbols.
For example, if I create a file foo.go with the following contents:
package main
import (
"C"
"fmt"
)
//export PrintInt
func PrintInt(x int) {
fmt.Println(x)
}
func main() {}
The important things to note are:
The package needs to be called main
You need to have a main function, although it can be empty.
You need to import the package C
You need special //export comments to mark the functions you want callable from C.
I can compile it as a C callable static library with the following command:
go build -buildmode=c-archive foo.go
The results will be an archive foo.a and a header foo.h. In the header, we get the following (eliding irrelevant parts):
...
typedef long long GoInt64;
...
typedef GoInt64 GoInt;
...
extern void PrintInt(GoInt p0);
...
So that's enough to call the exported function. We can write a simple C program that calls it like so:
#include "foo.h"
int main(int argc, char **argv) {
PrintInt(42);
return 0;
}
We can compile it with a command like:
gcc -pthread foo.c foo.a -o foo
The -pthread option is needed because the Go runtime makes use of threads. When I run the resulting executable it prints 42.
The code above work just fine, but gcc will complain about functions and headers.
The includes should be:
#define _GNU_SOURCE
#include <stdio.h>
#include "mygopkg.h"
If you forget the #define _GNU_SOURCE, the gcc will complain:
warning: implicit declaration of function 'asprintf'; did you mean 'vsprintf'? [-Wimplicit-function-declaration]
If you forget the #include "mygopkg.h", the gcc will complain:
warning: implicit declaration of function 'PrintString' [-Wimplicit-function-declaration]
The last but not less important. The build command line I recommend for production code is:
go build -ldflags "-s -w" -buildmode c-archive -o mygopkg.a
It'll save you 53% size of final mygopkg.a.

Link against a Windows .dll+.lib file combination with GCC under Cygwin?

I know how to link against libraries in Unix-ish contexts: If I'm working with .a or .so files, I specify the root search directory with -L/my/path/to/lib/ and for libMylib I add -lMyLib.
But what if I have
a .dll (e.g. in the Windows\System32 directory)?
a .dll (in Windows\System32) and a .lib (someplace else)?
These DLLs are by some other party; I don't have access to their sources - but do have access to the corresponding include files, against which I manage to compile.
If you can link against a .lib in Cygwin or MinGW, then you can (indirectly) link against a DLL.
In the MSVC world, it is not unusual to create an import library along with a DLL. It is a static library (.lib) that loads the DLL and wraps the interface of the DLL. You just call the wrapper functions in the (static) import library and let the import library do all the DLL-related things.
For the Windows API, there are import libraries in the WindowsSDK.
For your own MSVC DLLs, MSVC can automatically generate the import libraries when you build the DLL.
For a third party DLL, you can build a static wrapper library based on the corresponding header files.
Linking against the .lib file in Cygwin or MinGW is possible. Example:
g++ -o myprg myprg.o -lShlwapi
This links against Shlwapi.lib. (The library must be in the local directory or in the library path of the linker.)
Linking against import libraries of DLLs works the same way.
Note 1: Keep in mind the different ABIs and name mangeling. However, calling plain C functions in DLL or LIB files will work in most cases.
Note 2: Keep in mind that g++ requires the libraries to be specified in the correct order.
#einpoklum Converting my comment to an answer: #n.18e9 is correct in that you must use the full path name for the lib file without any -L or -l options.
g++ -o foo.exe foo.o c:\something\somethingelse\some.lib. You can also link directly to the Windows DLL file g++ -o foo.exe foo.o c:\something\somethingelse\some.dll.
Important - make sure you are linking to a lib file (and associated dll) generated for a 64-bit platform (on MSVC target X64, not Win32).
OK you wanted an example, well let's go.
Here are two examples using gcc/g++ to link to a Windows native DLL which exports plain C functions (using here x86_64-w64-mingw32/8.3.0 on Windows 10).
I'm using my own free xmlsq library as an example https://www.cryptosys.net/xmlsq.
You can download the core native DLL and all the source code quoted below. Make sure you use the 64-bit DLL.
The native Windows DLL diXmlsq.dll is written entirely in plain C code and exports simple C functions (extern "C").
In particular, for this example, it exports a XMLSQ_Gen_Version function that returns an integer value.
The DLL was compiled using MSVC 12.0 targetting the X64 platform. The associated library file generated by MSVC is diXmlsq.lib.
I should add that this DLL works exactly the same as a Windows "Win32 API" DLL, so the instructions here should work for the standard Windows libraries in Windows\System32 (again make sure you link against the 64-bit version).
Example 1. A plain C interface.
Both these commands compile without warning on my system:
> gcc -o test-ver test-ver.c "C:\fullpath\to\x64\diXmlsq.lib"
> gcc -o test-ver test-ver.c "C:\fullpath\to\x64\diXmlsq.dll"
diXmlsq.dll is compiled using the following definition file.
(You could alternatively use __declspec(dllexport))
Ref: https://learn.microsoft.com/en-us/cpp/build/exporting-from-a-dll?view=msvc-160
diXmlsq.def
LIBRARY "diXmlsq"
EXPORTS
XMLSQ_Gen_Version
diXmlsq.h - the C interface to diXmlsq.dll
#ifdef __cplusplus
extern "C" {
#endif
long __stdcall XMLSQ_Gen_Version(void);
#ifdef __cplusplus
}
#endif
To call the core function in a plain C program:
test-ver.c
#include <stdio.h>
#include "diXmlsq.h"
int main(void)
{
long n;
n = XMLSQ_Gen_Version();
printf("Version = %ld\n", n);
return 0;
}
Example 2. A C++ interface.
Both these commands compile without warning using g++ .
> g++ -o test-simple test-simple.cpp xmlsq.cpp "C:\fullpath\to\x64\diXmlsq.lib"
> g++ -o test-simple test-simple.cpp xmlsq.cpp "C:\fullpath\to\x64\diXmlsq.dll"
The idea of the C++ interface is to be an interface to the plain C library using the more convenient STL types like std::string and std::vector.
To keep things simple we'll just demonstrate the Gen::Version method.
Extracts of the C++ code follow:
test-simple.cpp - a test C++ program.
#include <iostream>
#include "xmlsq.hpp"
int main()
{
std::cout << "xmlsq::Gen::Version=" << xmlsq::Gen::Version() << std::endl;
}
xmlsq.hpp - the C++ interface
namespace xmlsq
{
class Gen {
private:
Gen() {} // Static methods only, so hide constructor.
public:
/** Get version number of core diXmlsq DLL. */
static int Version();
};
}
xmlsq.cpp - the C++ implementation.
#include "diXmlsq.h"
#include "xmlsq.hpp"
namespace xmlsq
{
int Gen::Version() {
int n = XMLSQ_Gen_Version();
return n;
}
}
Example 3. Attempting to link to the 32-bit library by mistake.
> gcc -o test-ver test-ver.c "C:\fullpath\to\Win32\diXmlsq.lib"
C:/Strawberry/c/bin/../lib/gcc/x86_64-w64-mingw32/8.3.0/../../../../x86_64-w64-mingw32/bin/ld.exe:
C:\Users\user\AppData\Local\Temp\cce27Dhl.o:test-ver.c:(.text+0xe):
undefined reference to `XMLSQ_Gen_Version'
collect2.exe: error: ld returned 1 exit status

Resources