How do I build a shared library using Go that calls an undefined c function? - cgo

I want to create a shared library, using Go, to be used by a third-party software (STAR-CCM+). That software provides some utility c functions for my code to call, and expects my code to, at a minimum, define a specific function, which the third-party software will call after loading the library.
My problem is Go complains about undefined references for the utility functions:
/tmp/go-build672782048/b001/_x002.o: In function `_cgo_c4b84da031f3_Cfunc_utility':
/tmp/go-build/cgo-gcc-prolog:50: undefined reference to `utility'
How can I compile a shared library that calls a c function that is declared but not defined by my code?
The third-party software provides a header file similar to this:
uclib.h
#ifndef UCLIB_H
#define UCLIB_H
// utility function defined by third party software, declared here
extern void utility(int);
// function expected to exist in .so and defined by user
// this function is expected to call `utility` one or more times
void user_function();
#endif
Working example, c only
To test the interaction with the third party software, I build an example using only c:
usingc.c
#include "uclib.h"
void
user_function()
{
utility(1);
}
Build:
$ gcc -fPIC -c usingc.c -o usingc.o
$ gcc -shared -o libmine.so usingc.o
This results in a libmine.so that the third party software successfully loads and registers its utility function being called with 1. Note that utility was only declared, never defined, by my code.
Problematic example, Go
I create a simple go module with the header above and two files:
go.mod
module example.com/cgo_mwe
go 1.15
usinggo.go
package main
// #include "uclib.h"
import "C"
//export user_function
func user_function() {
C.utility(C.int(2))
}
func main() {}
I attempt to build the shared library and observe the error:
$ go build -o libmineg.so -buildmode=c-shared
# example.com/cgo_mwe
/tmp/go-build672782048/b001/_x002.o: In function `_cgo_c4b84da031f3_Cfunc_utility':
/tmp/go-build/cgo-gcc-prolog:50: undefined reference to `utility'
collect2: error: ld returned 1 exit status

The are three possible solutions to allow the linking with the undefined reference. The second two are found in the golang-nuts Google Group:
ignore all undefined references via LDFLAGS with -shared
// #include "uclib.h"
// #cgo LDFLAGS: -shared
import "C"
ignore all undefined references via LDFLAGS with -Wl,-unresolved-symbols=ignore-all:
// #include "uclib.h"
// #cgo LDFLAGS: -Wl,-unresolved-symbols=ignore-all
import "C"
mark the declared but undefined functions as weak in the header file:
#pragma weak utility
// utility function defined by third party software, declared here
extern void utility(int);
The advantage of #3 is that references not marked weak are still called out as undefined.

Related

cgo calling a cpp function: producing error for _stprintf_s

On Windows, from a go code using CGO, I am calling a function from a cpp file.
The function (from the cpp file) calls _stprintf_s. When I comment call to this function, the go code builds fine.
But in presence of this call i get followin error
error: 'sprintf_s' was not declared in this scope
I have included the required <stdio.h> & <tchar.h> in cgo.
Not sure why _stprintf_s is producing this error. any help/pointers are welcome.

Trouble getting started with Metal shader compilation

I'm having trouble getting started with Metal's shader compilation.
How to make a MTLLibrary that can link to a MTLDynamicLibrary (or MTLLinkedFunctions), in particular a library that declares extern functions that are to be resolved at runtime when providing preloadedLibraries (or linkedFunctions) in the compute pipeline descriptor? For example, I can compile the following to air using xcrun metal (with option -c), but then invoking xcrun metallib (even with option --split-module-without-linking) gives the error LLVM ERROR: Undefined symbol: _Z3addjj. In other words, how do I make a 'partially bound' metal library?
// shader.h
extern uint add(uint a, uint b);
/// shader.metal
#include "shader.h"
kernel void kernel_func(uint gid [[ thread_position_in_grid ]]) { add(gid,2); }
WWDC2021 mentions this extern technique, but the Dynamic Library Code Sample from the previous year doesn't use extern (or the installName), so I don't make sense of it.
When creating an executable library that uses a dynamic library, there are two points where you must include the dynamic library (I thought there was only one).
The process is different depending on whether the executable source is compiled at build or runtime. I'll describe for the case of runtime, because I haven't yet figured out the case for the executable library created from a metallib file.
The first point is when you compile the executable, where you must include the dynamic library in the libraries field of the CompileOptions. The library is there at this point just as a dummy, to check that you have a dynamic library that defines the declarations allowing for proper linkage, though that linkage doesn't occur at this stage, just the checking.
The second point is when you create the pipeline state, where you must include the dynamic library in the preloadedLibraries field of the pipeline descriptor. This time, the dynamic library is not a dummy but the real library you plan to use, as it will be linked with the executable during pipeline creation.

XCode Build System: Messing up preprocessors definitions and included header files?

First question here.
I have some troubles with the XCode Build System, specifically with preprocessor definitions.
I'm trying to define a macro for the objective-c runtime to avoid enforcing the dispatch functions to be cast to an appropriate function pointer type. The usual way to go would be to use #define OBJC_OLD_DISPATCH_PROTOTYPES and then include the header on the next line. Once the header gets included, the macro is already defined and the header is configured accordingly.
But that's where it starts to get weird!
The macro is not recognized at all and the header gets included as if the #define statement was not there so it fails to #define OBJC_OLD_DISPATCH_PROTOTYPES and it gets (re?)defined as 0.
main.c
#include <stdio.h>
#define OBJC_OLD_DISPATCH_PROTOTYPES 1
#include <objc/objc-runtime.h>
int main(int argc, const char * argv[]) {
// From there:
// - Build System: OBJC_OLD_DISPATCH_PROTOTYPES is always 0, except if defined in build settings
// - Clang (only): OBJC_OLD_DISPATCH_PROTOTYPES is 1
printf("%d\n", OBJC_OLD_DISPATCH_PROTOTYPES);
}
The build system acts as expected when the preprocessor macro is defined in the project build settings under the "Apple Clang - Preprocessing" section. It defines the global macro using the -D parameter of clang making it available to any files used by the project.
However, source code compiles correctly when I use clang from a terminal using clang main.c.
Could someone tell me what I need to configure for the build system to behave normally?
It gives a warning when building with Xcode IDE:
Ambiguous expansion of macro 'OBJC_OLD_DISPATCH_PROTOTYPES'
and the output is indeed 0 using Xcode directly, but 1 with clang main.c. The difference is that Xcode uses clang with enabled modules by default: You get the same warning on the command line if you enable modules there:
clang -fmodules main.c
Solution
In Xcode, select the target, go to the "Build Settings" tab and in the "Apple Clang - Language - Modules" section, switch the "Enable Modules (C and Objective-C)" entry to 'NO':
Then you get the expected result in both cases, regardless of whether you use Xcode or Clang on the command line.
Explanation:
If you use modules the following happens:
instead of the preprocessor including the text and compiling the result, a binary representation of the module is used
modules are (independently) precompiled, i.e. they use the definitions from the time the module was precompiled
consequently, preprocess definitions from the code before the include/import statement have no effect on the module (nor on other imported modules).
if modules are enabled, not only #imports are affected, but also #includes are translated into module imports under the hood
So you have a contradictory definitions for the OBJC_OLD_DISPATCH_PROTOTYPES.
The precompiled module uses a 0 for OBJC_OLD_DISPATCH_PROTOTYPES and you redefine it as 1.
BTW: if you use
#define OBJC_OLD_DISPATCH_PROTOTYPES 0
then you use the same definition that the precompiled module is using and therefore there is no warning about an ambiguous expansion of the macro even if modules are enabled.
Without enabled modules, the preprocessor includes the text, compiles the result and returns the expected result, i.e. in objc.h the desired typedef are used.

Lua - "multiple vms detected" while trying to add extension for statically linked Lua

I have application that contain statically linked lua 5.2 inteperpreter (and haven't access to code).
When I trying to write extension with next code:
#define LUA_LIB
#define LUA_BUILD_AS_DLL
#include "lua.hpp"
extern "C"
{
static int test(lua_State* state)
{
return 1;
}
static const struct luaL_Reg functions[] = {
{"test", test},
{NULL, NULL},
};
int __declspec(dllexport) luaopen_test(lua_State* state)
{
luaL_newlibtable(state, functions);
luaL_setfuncs(state, functions, 0);
return 0;
}
}
And compile it with statically linked lua52.lib .
I get "multiple vms detected" error when I trying to require it fromn lua code.
What I can do in this situation?
You can't compile it with statically linked lua52.lib as the main application loads its own version of lua52.lib and when this module is "required", it loads its own copy, which leads to "multiple VMs detected" message.
With statically compiled VM you have two options (on Windows): (1) include all your modules statically, or (2) compile your modules against Lua52.dll, but instead of the actual DLL include a "proxy" DLL that will forward Lua API calls to the methods in the statically compiled executable (the API methods also need to be exported in the executable).
See this thread for the discussion on how the executable needs to be compiled and LuaProxyDllFour page for the proxy DLL.
On Linux you don't need to have a proxy library, but you still need to avoid linking Lua interpreter into the library and export symbols from the executable by using -Wl,-E linker option; see lhf's answer for details.

Undefined symbol on xcode with custom library for ios (definition of the symbol is there)

I know there are other questions with that same title, but none of them have the same problem than me.
I have two projects. One of them builds a library, the other one builds an app that uses that library.
When I build the library it's all ok. It creates a .a file which contains the library. When I try to build the second project, I get the following message:
Undefined symbols for architecture armv7:
"_SPLite3_rtree_geometry_callback", referenced from:
_register_spatialite_sql_functions in liblibspatialite.a(spatialite.o)
ld: symbol(s) not found for architecture armv7
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Thats bad. At first I did not know what it was talking about, but after some research, found that the library may have not be built for armv7, so I used the lipo command to check the architecture:
lipo -info liblibspatialite.a
This produces the following output.
Non-fat file: liblibspatialite.a is architecture: armv7
Ok so the architecture is right. Then what? Maybe check for the symbols of the .o files that will conform the library. For that I used the nm command:
nm spatialite.o | grep SPLite3_rt
Which produces the following output:
U _SPLite3_rtree_geometry_callback
I checked the manpage for nm and saw that the U before the symbol means it's undefined. So it seems that's it. The symbol appears as undefined. I have another version of the project in another workspace. I've checked, and it produces a working library. The nm command returns the following on that other version:
0000e5f6 T _SPLite3_rtree_geometry_callback
0018c668 S _SPLite3_rtree_geometry_callback.eh
So, with this library it's working and it's fine. I've tried to find differences in the build options of both projects but they look the same to me.
I can build with the first version of the library if I include the source files of the library in the compiler section of the properties of the project. (Select target -> Build phases -> Compile sources), but I think that's not the point of using a library.
So, I'd like to know what can I do so that the _SPLite3_rtree_geometry_callback gets included in the library.
Thanks in advance.
EDIT:
Some more info. In spatialite.c, there is the following code:
#define sqlite3_rtree_geometry_callback SPLite3_rtree_geometry_callback
SQLITE_API int sqlite3_rtree_geometry_callback(
sqlite3 *db,
const char *zGeom,
int (*xGeom)(sqlite3_rtree_geometry *, int nCoord, double *aCoord, int *pRes),
void *pContext
);
EDIT 2:
Code for the method:
/*
** Register a new geometry function for use with the r-tree MATCH operator.
*/
SQLITE_API int sqlite3_rtree_geometry_callback(
sqlite3 *db,
const char *zGeom,
int (*xGeom)(sqlite3_rtree_geometry *, int, double *, int *),
void *pContext
){
RtreeGeomCallback *pGeomCtx; /* Context object for new user-function */
/* Allocate and populate the context object. */
pGeomCtx = (RtreeGeomCallback *)sqlite3_malloc(sizeof(RtreeGeomCallback));
if( !pGeomCtx ) return SQLITE_NOMEM;
pGeomCtx->xGeom = xGeom;
pGeomCtx->pContext = pContext;
/* Create the new user-function. Register a destructor function to delete
** the context object when it is no longer required. */
return sqlite3_create_function_v2(db, zGeom, -1, SQLITE_ANY,
(void *)pGeomCtx, geomCallback, 0, 0, doSqlite3Free
);
}
Check that spacialite.c is added to the library's target.
You have to specify SQLITE_ENABLE_RTREE in preproccessor macro
Ok. This seems weird but it looks like I finally fixed it. Everything is correctly defined, so why it is not working I don't know.
I was using the xcode target preferences to define the preprocessor macros. Instead of that, I changed the SQLITE_ENABLE_RTREE to the .pch file, and after that the build contains the missing symbol.

Resources