Export a variable when building a shared object using cgo - c

I want to build a .so library using Go/Cgo with options go build -buildmode=c-shared.
Functions exports well, but I cannot export variables. I need to realize an API, which works by calling a void function, which sets up values of various global properties. Something like this:
var (
Gval1 int
Gval2 string
//GvalN
)
func f(){
Gval1 = 1
Gval2 = "qwerty"
}
The client of .so lib will run f(); and after that, it can get variables by addressing their names. How can I export them?
I had tried to do a trick like this: golang cgo can't export variables by build mode c-shared, but there was no success (example returns always 0, not 42).
How can I export variables (numbers and strings)?

I don't think you can export variables, only functions.
The go build documentation says:
-buildmode=c-shared
Build the listed main package, plus all packages it imports,
into a C shared library. The only callable symbols will
be those functions exported using a cgo //export comment.
Requires exactly one main package to be listed
Where the cgo docs says
Go functions can be exported for use by C code in the following way:
I guess you can write a function that returns the variable value.

Related

Is there a way to use Zap structured logger in Go and export it to be called in a C script using cgo?

I am trying to use Cgo to export a function that initializes a zap logger. The function is written in Go but I am working towards the goal of being able to call this function in a C script and actually use the function in the C script. For example, my init function looks like this:
func initLogger() *zap.Logger {
logger, _ := zap.NewProduction()
return logger
}
Now, I want to be able to use this function in a c script by exporting it using cgo. So, I would do //export initLogger and then build a .so and .h file from this go file and link it to a c script to build an executable. So basically, in my C script, I want to be able to do something like :
logger = initLogger()
logger.Info("Hello World!")
This would log:
{"level":"info","ts":1654031030.1591902,"caller":"go-kitLog/exLogger.go:14","msg":"Hello World!"}
The problem I am facing is that *zap.Logger does not export to C, it gives this error: Go type not supported in export: *zap.Logger. Have any of you possibly dealt with a similar situation? If so, how did you solve it?

Sharing C functions between two XS Perl modues

I have a Perl module A that is a XS based module. I have an A.xs file, and an aux_A.c file, where I have some standard C functions. I use DynaLoader, and it works file.
Now, I have a new module B, that is also a XS module. I also have the B.xs file, and the aux_B.c file. Now, I want that a standard C function defined in aux_B.c file to be able to use a function defined in aux_A.c file.
One option is to make A module to create a standard C library, and link B module with it. But I was trying to get away from that option.
Is there any other way to go?
What I am currently getting is DynaLoader complaining on undefined symbol when trying to load the B.so library.
Thanks
Alberto
To make module A export its C symbols with DynaLoader, you have to add the following to A.pm:
sub dl_load_flags { 1 }
This is badly documented, unfortunately. See this thread on PerlMonks and the DynaLoadersource code for more details. The effect of the flag is to set RTLD_GLOBAL when loading A.so with dlopen which makes its symbols available to other shared objects.

How to generate a hex without main function using IAR linker - xlink?

The point is to generate a hex without main function using IAR linker - xlink?
This code should be loaded into the RAM of RL78 MCU.
A quick Google search of iar generate hex from library brought me to this document, "Creating an Absolutely Placed Library", as a first result. It has all the information you need, plus some information on using a CRC for consistency checking. The document is for the IAR EWRX variant, but the concepts should all be the same.
The basic process is to compile your library as an executable, but without a main() function in it. You'll need to set your library configuration under General -> Library Options to None. You can also setup your file conversion settings at this point.
Since you don't have a main() function for a program entry point, you will need to create an entry function to call the IAR C runtime initialization function, __iar_data_init2(), and then set the linker to use this function as the entry point (which can be found under Linker Options -> Library Options).
When building a library, all the symbols will be preserved until the final link step for the application using it, but since you are building this as an executable, it is important that the symbols you want to keep have the __root keyword, or under Linker -> Extra Options you can specify --no-remove to keep all symbols.
In the next step, you need to use isymexport to export the symbols that you want. You will need a file to direct the tool what to export. In the example, they have a file that just contains the following:
show lib_*
show __checksum*
This will direct the tool to export all symbols beginning with lib_ and all symbols beginning with __checksum. They note that __iar_data_init2() should not be exported, as this would cause conflicts with the application that ultimately will use this code. You invoke the tool like so:
isymexport <path to .out file> <path to output from tool> --edit <path to file created above>
Now you should have the output from isymexport and the library file that you were looking for. For the application using this library, you'll need to add the output from isymexport as a library under Linker -> Library, and in your application, you'll need to call your entry function in the library before you attempt to use any of the library's symbols.
This should be the information you need to generate a library that lives in a hex file and can be loaded separately, as well as how to use that library. The referenced document has a lot more detail, so if it is available at that link (or can be found elsewhere by title) it will be a better reference than my summary here.

Symbols stay local and not exported properly

A colleague gave me a modified version of a shared library where he added a GTK widget.
When inspecting the shared library file I see that the new widget functions are defined as local and not global.
I have tried to set the visibility attribute of GCC on the function (after the declaration itself, before the semicolon), it has G_BEGIN_DECLS around it and the same common headers and defines as other files in the library that are exported properly.
Is there a linker command line option I may be missing? A list of files that "can" export that is used by gcc, perhaps another definition for exported functions?
When inspecting the shared library file I see that the new widget functions are defined as local and not global.
By default, all symbols in a shared library are exported (unless you compile with -fvisibility=hidden or protected.
Since observe that your symbols are LOCAL, it is a good bet that your link command uses a linker version script to control symbol visibility (to hide all symbols except ones that are explicitly exported), and that you have not modified that version script to add your functions to the export list.
Look for -Wl,--version-script=... on your link command line, and modify the version script appropriately.
See also this answer.
I've found out that the library uses a regular expression to filter exports (the -export-symbols-regex switch), adding another regular expression made the symbols properly exported, now I everything is linking properly.

How can I use VTD-XML inside Perl with Inline::C?

I've recently discovered the power of the VTD-XML approach to XML parsing, mainly its speed.
Just to be specific, I have built the C version 2.10 ( there are Java, C++ and C# implementations too ).
My objective is simple: I want to extract data from XML using VTD-XML for parsing, and using Perl to work with data.
The easy way may be dump data with a C program I made, and send them via pipe to the Perl program. Maybe not elegant but it works.
Another, less easy way, consists of a Perl program that calls the C data collector subroutine using Inline::C.
So I started studying Inline::C and managed to do basic things I need to pass data back to Perl from C subroutines using Perl C API functions.
Problems arise in the compiling phase when I write the C collector subroutine in the C source under Inline::C control.
There are symbol conflicts like this: bind() is defined both in socket.h ( Perl ) and in autoPilot.h ( VTD-XML ). Symbol conflicts can be avoided building VTD-XML as a shared library with an explicit export map ( gcc -Wl,-version-script=foo.map )... Is this the right way to go?
Are there better ways?
I did reach my goal by adding a layer of indirection: awful, as it seems to me it works.
First of all, I made a shared library containing the VTD-XML API. Building this shared object, I had to avoid global scope pollution, exporting only symbols needed.
Then I built another shared library. This second shared libray hides the VTD-XML API and is supposed to be used from Perl via Inline::C. In this shared object I wrote a handful of functions, using libvtd.so partially exposed API.
The idea looks like this:
Perl -> Inline::C dynamic loader -> wrapper_API.so -> libvtd.so
Major issues came from runtime loading of shared libraries and from symbol collision/resolution.
Here is how I build libvtd.so, making it easy for the so called wrapper_API.so to use it.
Unfortunately, VTD-XML doesn't build a libvtd.so shared object, so I had to build it myself linking together several .o object files with gcc:
gcc -shared -fPIC -Wl,-soname,libvtd.so.2.10 -Wl,--version-script=vtd-xml.map \
-o libvtd.so.2.10 libvtd.o arrayList.o fastIntBuffer.o fastLongBuffer.o \
contextBuffer.o vtdNav.o vtdGen.o autoPilot.o XMLChar.o XMLModifier.o intHash.o \
bookMark.o indexHandler.o transcoder.o elementFragmentNs.o
Symbol visibility was tuned with the linker option -Wl,--version-script=vtd-xml.map, where the map file being:
{
global:
the_exception_context;
toString;
getText;
getCurrentIndex;
toNormalizedString;
toElement;
toElement2;
createVTDGen;
setDoc;
parse;
getNav;
freeVTDGen;
freeVTDNav;
getTokenCount;
local:
*;
};
Global ( "exported" ) symbols are under the global: section, while the catchall * under local says all other symbols are only known locally.
All object modules come from the VTD-XML distribution, with the exception of libvtd.o: this custom object was needed to address issues with exception handling library cexept.h.
libvtd.c is only two lines of code.
#include "customTypes.h"
struct exception_context the_exception_context[ 1 ];
In the compilation phase I had to adjust CFLAGS of to make Position Independent Code ( gcc -fPIC option ), in order to make shared objects.
readelf tool was useful to check symbol visibility:
readelf --syms libvtd.so.2.10
Symbol table '.dynsym' contains 35 entries:
Num: Value Size Type Bind Vis Ndx Name
...
280: 000000000000d010 117 FUNC LOCAL DEFAULT 12 writeIndex
281: 000000000003c5d0 154 FUNC LOCAL DEFAULT 12 setCursorPosition
282: 000000000003c1f0 56 FUNC LOCAL DEFAULT 12 resetIntHash
...
331: 0000000000004f50 3545 FUNC GLOBAL DEFAULT 12 toElement
332: 00000000000071e0 224 FUNC GLOBAL DEFAULT 12 getText
333: 000000000000d420 114 FUNC GLOBAL DEFAULT 12 freeVTDGen
...
339: 000000000000b600 731 FUNC GLOBAL DEFAULT 12 toElement2
340: 000000000000e650 120 FUNC GLOBAL DEFAULT 12 getNav
341: 0000000000025750 70567 FUNC GLOBAL DEFAULT 12 parse
The wrapperAPI.so consists of several functions that use VTD-XML API, its custom types, but accept and return only standard C types and/or structs.
The wrapper came straight from a former standalone C program.

Resources