Provide fallback symbol for dynamic linking - ios

When dynamically linking a library is there a way to specify a fallback symbol in case one is missing at load time.
For example compiling a MEX file instead of mxCreateNumericArray I'd like to call mxCreateUninitNumericArray (with same signature). But the latter won't be present for older MATLAB versions. Same for mxArrayToString and mxArrayToUTF8String.
For MSVC I've been able to use /DELAYLOAD and hook into __pfnDliFailureHook2 on dliFailGetProc to provide a simple mapping. But what can I do on Unix based systems?
How to hook into libld in a similar way?

I've not been able to hook into the dynamic linker, but providing weak symbols helped me out like this:
extern "C"
char * __attribute__ ((weak)) mxArrayToUTF8String( mxArray const * array )
{
return mxArrayToString( array ) ;
}

Related

How to reflect Dart library name?

Is there a way to reflect specific library properties (like the library name) in Dart?
How do you get the library object reference?
First of all, not all Dart libraries have names. In fact, most don't. They used to, but the name isn't used for anything any more, so most library authors don't bother adding a name.
To do reflection on anything, including libraries, you need to use the dart:mirrors library, which does not exist on most platforms, including the web and Flutter.
If you are not running the stand-alone VM, you probably don't have dart:mirrors.
With dart:mirrors, you can get the program's libraries in various ways.
library my.library.name;
import "dart:mirrors";
final List<LibraryMirror> allLibraries =
[...currentMirrorSystem().libraries.values];
void main() {
// Recognize the library's mirror in *some* way.
var someLibrary = allLibraries.firstWhere((LibraryMirror library) =>
library.simpleName.toString().contains("name"));
// Find the library mirror by its name.
// Not great if you don't know the name and want to find it.
var currentLibrary = currentMirrorSystem().findLibrary(#my.library.name);
print(currentLibrary.simpleName);
// Find a declaration in the current library, and start from there.
var mainFunction = reflect(main) as ClosureMirror;
var alsoCurrentLibrary = mainFunction.function.owner as LibraryMirror;
print(alsoCurrentLibrary.simpleName);
}
What are you trying to do, which requires doing reflection?

Ada library initialisation/elaboration and GPR directives : can't find elaboration symbol

I am trying to produce an Ada library for iOS.
However, it is necessary to perform the Ada elaboration manually.
I know that the compiler can produce an init symbol, that can be later imported and used. However, with the following GPR definition, it is not produced (the nm command does not list it). The naming is supposed to be <libname>init with <libname> corresponding to the value defined in the GPR directive Library_Name
The GPR is defined in the following fashion (this one is windows/style -see DLL references-, but the problems also applies when producing for iOS on a Mac):
project adalib is
for Languages use ("Ada");
for Source_Dirs use (project'Project_Dir & "./src");
for Library_Kind use "static"; --"static" on iOS will produce a .a file
for Library_Name use project'Name; -- will produce "libadalib.a"
for Library_Dir use project'Project_Dir & "./lib";
for Library_Src_Dir use project'Project_Dir & "./includes";
-- define your favorite compiler, builder, binder, linker options
end adalib;
I'm missing it : how to produce that symbol ?
I found the solution.
My GPR was missing this simple directive:
for Library_Interface use ("mypackage"); -- put whatever packages you want to expose, without .adb/.ads since we're talking about packages
With the above directive, I can find the adalibinit symbol via nm command.
When I import it in my ada code, I can also use it, see :
package body mypackage is
procedure Init_My_Lib
is
-- I want to call elaboration;
pragma import (C, ada_elaboration, "adalibinit");
begin
ada_elaboration;
-- further code
end Init_My_Lib;
-- rest of package
So, the full GPR should be:
project adalib is
for Languages use ("Ada");
for Source_Dirs use (project'Project_Dir & "./src");
for Library_Kind use "static"; -- will produce a .a file
for Library_Name use project'Name; -- will produce "libadalib.a"
for Library_Interface use ("mypackage"); -- <=== THIS IS HERE
for Library_Dir use project'Project_Dir & "./lib";
for Library_Src_Dir use project'Project_Dir & "./includes";
-- define your favorite compiler, builder, binder, linker options
end adalib;

Unmanaged C# calls to a static library

I'm using swig to generate C# wrappers for some C code base to be used from C#. When I run swig, it generates a wrapper c file that exposes all the functionality to the generated PInvoke C# file... For example:
// This is in KodLogic_wrap.c
SWIGEXPORT void SWIGSTDCALL CSharp_DMGameMode_timeLimit_set(void * jarg1, unsigned short jarg2) { ... }
// This is in KodLogicPInvoke.cs
[global::System.Runtime.InteropServices.DllImport("KodLogic", EntryPoint="CSharp_DMGameMode_timeLimit_set")]
This works great when I am building a dynamic library. However, I need to support iOS now, so I've prepared a static library, and passed in the -dllimport '__Internal' option to swig for that to work.
Unfortunately, I am getting linking errors such as:
"_DMGameMode_timeLimit_set", referenced from:
RegisterMonoModules() in RegisterMonoModules.o
(maybe you meant: _CSharp_DMGameMode_timeLimit_set)
Indeed, I did mean "CSharp_DMGameMode_timeLimit_set", but that's the point of the "entrypoint" argument?
So, since this error is thrown by the Xcode project Unity generated, I am not quite sure what's the source of the failure. Does it fail for static libraries? Is this something to be fixed on Unity side or swig side?
Update: After digging more into this, I think I have a slight idea of what's going on here..
The main issue seems to be from the AOT compiler, which tries to compile all the CS code to an ARM assembly. This seems to be required for iOS, so during Unity's AOT compilation, it generates a file RegisterMonoModules.cpp, which attempts to define access functions to the native code. RegisterMonoModules.cpp doesn't honor the entrypoint parameter, which causes undefined symbol errors to be thrown...
Still attempting to find a proper workaround.
The main issue seems to be from Unity, and not Swig nor Mono. As mentioned above, Unity performs AOT compilation that doesn't honor the entry point argument. This produces cpp code that calls the function name, not the entry point name..
I've confirmed this by switching the scripting backend to IL2cpp, and the entry point name was honored there.
Let's switch over to callbacks. Not exactly related to the question, but it definitely fits the context of Unity + Native plugins + iOS.
AFAIK, you can't have a managed method marshaled to native land on iOS using Mono 2x. I previously had to delete all the string callback and exception handlers from the swig generated files. Fortunately, IL2Cpp supports callbacks, after a little tweaking:
Add using AOT;
Decorate callbacks with [MonoPInvokeCallback(typeof(method_signature))]
You can use this script, just use it to process the generated swig files:
def process_csharp_callbacks(pinvoke_file):
"""Process PInvoke file by fixing the decorators for callback methods to use:
[MonoPInvokeCallback(typeof(method_signature))]
"""
# prepare requirements
with open(pinvoke_file) as f:
content = f.read()
callback_methods_regex = re.compile(r"( +)static (?:void|string) (?:SetPending|CreateString)\w*\([\s\w\,]+\)")
callback_decorator = "[MonoPInvokeCallback(typeof(ExceptionDelegate))]"
callback_arg_decorator = "[MonoPInvokeCallback(typeof(ExceptionArgumentDelegate))]"
callback_str_decorator = "[MonoPInvokeCallback(typeof(SWIGStringDelegate))]"
# add use AOT
content = content.replace("\n\n", "\nusing AOT;\n", 1)
# fix callback methods
def method_processor(match):
match_string = match.group()
indentation = match.captures(1)[0]
if match_string.find(",") != -1:
fix = callback_arg_decorator
elif match_string.find("static string") != -1:
fix = callback_str_decorator
else:
fix = callback_decorator
return indentation + fix + "\n" + match_string
content = callback_methods_regex.sub(method_processor, content)
# write it back
with open(pinvoke_file, "w+") as f:
f.write(content)
For anyone looking for help converting their generated swig CSharp PInvoke file to something mono 2x scripting backend will allow, stick this somewhere in your build process, after the CSharp files are generated:
pinvoke_template = """{extern_prefix} CSharp_{method_signature};
{normal_prefix} {method_signature} {{
{return_statement}CSharp_{method_name}({method_args});
}}"""
def process_csharp_wrapper(csharp_dir):
"""Reads the PINVOKE csharp file, and performs the following:
1. Remove EntryPoint="xxx" from the decorators
2. Make the methods match their native counterpart name
3. Add a C# method with the original name, for compatability
"""
# prepare requirements
pinvoke_file = os.path.join(csharp_dir, "KodLogicPINVOKE.cs")
with open(pinvoke_file) as f:
content = f.read()
decorator_regex = re.compile(r', EntryPoint=".*?"')
method_regex = re.compile(r"(public static extern \w+[\w:\.]+)\s(([^S]\w+)\((?:([\w:\. ]+)\,?)*\));")
# fix decorators
content = decorator_regex.sub("", content)
# fix method definitions
def method_processor(match):
extern_prefix = match.captures(1)[0]
return pinvoke_template.format(
extern_prefix=extern_prefix,
normal_prefix=extern_prefix.replace("extern ", ""),
method_signature=match.captures(2)[0],
return_statement=("return " if extern_prefix.find("void") == -1 else ""),
method_name=match.captures(3)[0],
method_args=", ".join(map(lambda s: s.strip().split()[1], match.captures(4)))
)
content = method_regex.sub(method_processor, content)
# write it back
with open(pinvoke_file, "w+") as f:
f.write(content)

Calling Library in Lua

I have created a Wireshark dissector in Lua for an application over TCP. I am attempting to use zlib compression and base64 decryption. How do I actually create or call an existing c library in Lua?
The documentation I have seen just says that you can get the libraries and use either the require() call or the luaopen_ call, but not how to actually make the program find and recognize the actual library. All of this is being done in Windows.
You can't load any existing C library, which was not created for Lua, with plain Lua. It's not trivial at least.
*.so/*.dll must follow some specific standard, which is bluntly mentioned in programming in Lua#26.2 and lua-users wiki, code sample. Also similar question answered here.
There are two ways You could solve Your problem:
Writing Your own Lua zlib library wrapper, following those standards.
Taking some already finished solution:
zlib#luapower
lua-zlib
ffi
Bigger list #lua-users wiki
The same applies to base64 encoding/decoding. Only difference, there are already plain-Lua libraries for that. Code samples and couple of links #lua-users wiki.
NOTE: Lua module package managers like LuaRocks or
LuaDist MIGHT save You plenty of time.
Also, simply loading a Lua module usually consists of one line:
local zlib = require("zlib")
The module would be searched in places defined in Your Lua interpreter's luaconf.h file.
For 5.1 it's:
#if defined(_WIN32)
/*
** In Windows, any exclamation mark ('!') in the path is replaced by the
** path of the directory of the executable file of the current process.
*/
#define LUA_LDIR "!\\lua\\"
#define LUA_CDIR "!\\"
#define LUA_PATH_DEFAULT \
".\\?.lua;" LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" \
LUA_CDIR"?.lua;" LUA_CDIR"?\\init.lua"
#define LUA_CPATH_DEFAULT \
".\\?.dll;" LUA_CDIR"?.dll;" LUA_CDIR"loadall.dll"
#else
How do I actually create or call an existing c library in Lua?
An arbitrary library, not written for use by Lua? You generally can't.
A Lua consumable "module" must be linked against the Lua API -- the same version as the host interpreter, such as Lua5.1.dll in the root of the Wireshark directory -- and expose a C-callable function matching the lua_CFunction signature. Lua can load the library and call that function, and it's up to that function to actually expose functionality to Lua using the Lua API.
Your zlib and/or base64 libraries know nothing about Lua. If you had a Lua interpreter with a built-in FFI, or you found a FFI Lua module you could load, you could probably get this to work, but it's really more trouble than it's worth. Writing a Lua module is actually super easy, and you can tailor the interface to be more idiomatic for Lua.
I don't have zlib or a base64 C library handy, so for example's sake lets say we wanted to let our Lua script use the MessageBox function from the user32.dll library in Windows.
#include <windows.h>
#include "lauxlib.h"
static int luaMessageBox (lua_State* L) {
const char* message = luaL_checkstring(L,1);
MessageBox(NULL, message, "", MB_OK);
return 0;
}
int __declspec(dllexport) __cdecl luaopen_messagebox (lua_State* L) {
lua_register(L, "msgbox", luaMessageBox);
return 0;
}
To build this, we need to link against user32.dll (contains MessageBox) and lua5.1.dll (contains the Lua API). You can get Lua5.1.lib from the Wireshark source. Here's using Microsoft's compiler to produce messagebox.dll:
cl /LD /Ilua-5.1.4/src messagebox.c user32.lib lua5.1.lib
Now your Lua scripts can write:
require "messagebox"
msgbox("Hello, World!")
Your only option is to use a library library like alien. See my answer Disabling Desktop Composition using Lua Scripting for other FFI libraries.

Export C functions for LabView with c++builder

I have a DLL that I have ported from VC2008 to C++ Builder XE2. The DLL is used in LabVIEW's TestStand.
TestStand, when importing the VC2008 DLL, can see the function names and their arguments. When using the C++ Builder DLL, all its sees are the function names and not the arguments. All exports are C functions and use extern "C" declspec( dllexport ).
Is there a way to get the exports correct?
I have read that adding a TLB file will do the job, if this is true, how do I create a TLB that exports only C functions?
TestStand can read a .c/.cpp file and derive parameters from that file. You still load the DLL and select the function you want to call. You then 'verify' the parameters and select the .c/.cpp file in the dialog. TestStand will find the function with the same name and insert the parameters itself.
The function must be very specific, I had to create a dummy .c file that contained the prototypes as TestStand could not handle the #defines for dllexport and dllimport. It likes a very specific format. For the function:
TESTAPI bool StartTest( long inNumber ) {}
where TESTAPIis either extern "C" __declspec( dllexport ) or extern "C" __declspec( dllimport I had to write the line below in my dummy file:
bool __declspec( dllexport ) StartTest( long inNumber ) {}
That does it.
DLL function parameters cannot be determined from exports alone, unless they are being decorated by the calling convention (which is unusual to do in a DLL). If a TLB (aka a Type Library) solves the problem, then the VC2008 DLL is likely an In-Process ActiveX/COM object rather than a flat C DLL. If so, then in C+Builder you can use the IDE wizards on the "File | New" menu to create an "ActiveX Library" project, then a "COM Object" to add to the library. Then you will have a TLB that you can define your object with, and the IDE will generate stub code that you can fill in with your object's implementation.
If that is not what LabViews is expecting, then I suggest you contact them and ask. If all it needs is a TLB with flat C functions (which is very unusual, because TLB's are object-oriented), then you can omit the "COM Object" portion and just create an "ActiveX Library" project to get a bare-bones TLB, then add your definitions to it as needed, an then add your exports to the project.
From the reference here:
Avoid using the extern "C" syntax to export symbols. The extern "C" syntax prevents the C/C++ DLL Adapter from obtaining type information for function and method parameters."
A little late to the game, but your problem may be that C++ Builder is decorating the exported function with a leading underscore. The TLIB command line utility should help prove this (assuming tlib still ships with C++Builder)
TLIB mydll.lib, mydll.lst
Look at the resulting lst file and see if it contains StartTest or _StartTest. LabView is probably expecting to find a function without the underscore.
You can add a DEF file to your C++Builder project that will suppress the leading underscore. Try this:
Use the __cdecl calling convention instead of __stdcall.
Export plain "C" functions. No C++ classes or member functions.
Make sure you have an extern "C" {} around your function prototypes.
Create a DEF file that aliases the exported functions to a Microsoft
compatible name. Alias the names so they don't contain a leading
underscore. The DEF file will look like this:
EXPORTS
; MSVC name = C++Builder name
StartTest = _StartTest
Foo = _Foo
Bar = _Bar
5- Add the DEF file to your BCB DLL project and rebuild it.
Check out these ancient articles for more details:
http://bcbjournal.org/articles/vol4/0012/Using_Visual_C_DLLs_with_CBuilder.htm
The reverse article (creating C++Builder DLLs that get called from VC++ created applications) is buried in this archive:
http://www.frasersoft.net/program/bcbdev.zip : /articles/bcbdll.htm. It describes the DEF file trick in more detail, plus some other options.
Note that my answer is based on the way thing were in 1998 or so. They may have changed since then. If they have, then the C++Builder command line tools impdef, tlib, tdump, plus the Microsoft equivalents of those tools, should be able to show you exactly what is in your DLL vs the MSVC one.
H^2
I suggest to use ActiveX object: you can create an automation object in C++Builder and in Labview / TestStand you can import this object. If you use automation, in Lavbiew you will have the correct parameter definition. Make sure you are using a set of compatible type variables with Labview / TestStand.
For example, this fragment of code is the implementation of an array passed from Labview to C++:
STDMETHODIMP TCanLibraryImpl::DataDownload(VARIANT Data, long* RV)
{
_precondition_cmodule();
*RV = 0;
TSafeArrayLong1 mySafeArray(Data.parray);
int dLen =mySafeArray.BoundsLength[0];
...
}
In Labview you will pass to this function an array of I64

Resources