COMMUNITY

How to compile c with different function name with hxcpp

I want to compile some c program as a haxe library In this program they use some “val_int” “val_float” “val_string” fields. This causes some problems as haxe CFFI uses the same names for the fields.

How can I rename the original c program without modifying the c files. I was thinking of using the gcc preprocessor -D flag

(like in this example)

gcc -c foo.c -Dfoo=foo_renamed

but it doesn’t seem to work. Is there a way through Build.xml to do a grep or search and replace before compiling a file ?

Are you wedded to loading the library dynamically at runtime? Given the original C program presumably doesn’t need to know about haxe types I wonder if you can just use externs and regular C library linking rather than the CFFI system

Here’s a working example (haxe 4.2+):
ExampleLib.c

#include <stdio.h>

int add(int a, int b) {
	return a + b;
}

void sayHello(const char* message) {
	printf("Printing from C: %s\n", message);
}

ExampleLib.h

#ifndef ExampleLib_h
#define ExampleLib_h

#ifdef __cplusplus // when our lib is used from a C++ compiler, we need to wrap with extern "C"
extern "C" {
#endif

int add(int a, int b);

void sayHello(const char* message);

#ifdef __cplusplus
}
#endif

#endif

You can write externs to use this lib like so:

ExampleLib.hx

@:include('./ExampleLib.h')
@:sourceFile('./ExampleLib.c')
extern class ExampleLib {

	// we use native because we don't want ExampleLib:: namespace prefix
	@:native('add')
	static function add(a: Int, b: Int): Int;

	@:native('sayHello')
	static function sayHello(message: cpp.ConstCharStar): Void;

}

The @:sourceFile() meta adds the ExampleLib.c file to the hxcpp compilation so it’s compiled along with everything else.

Alternatively, you might want to compile the C code into a native library binary, either static (.a, .lib) or dynamic (.dll, .dylib, .so). One way to do this is to use @:buildXml to add linker flags that link with your static or dynamic library

Good Idea. I’ll give it it a try. I’ve never used externs before, that’s a good opportunity to start !

Good luck :), here’s a working example of the snippet above: https://github.com/haxiomic/haxe-c-bridge/files/6394311/hxcpp-c-link.zip

Hxcpp documentation isn’t as good as it could be so at present one of the best ways of learning about possibilities is by checking out the test/ directory in the hxcpp github: hxcpp/test at master · HaxeFoundation/hxcpp · GitHub

Feel free to ask again here if you run into issues or have any questions :slight_smile:

How did you guess I would have issues ? :wink:

My Main.hx

class Main{

public static function main() {

	Flite.flite_init();
}

}

My Flite.hx

@:buildXml('
<files id="haxe">  # I put this because https://wighawag.com/blog/2014/12/hxcpp-externs/
<compilerflag value="-Iinclude"/>
# This part is simplified, there are far more files
    <compilerflag value="-Iinclude/"/>
    <file name="flite/src/synth/cst_utt_utils.c"/>
    <file name="flite/src/synth/cst_ffeatures.c"/>
    <file name="flite/src/synth/cst_ssml.c"/>
    <file name="flite/src/synth/flite.c"/>
    <file name="flite/src/synth/cst_voice.c"/>
    <file name="flite/src/synth/cst_phoneset.c"/>
    <file name="flite/src/synth/cst_synth.c"/>

  </files>
<files id="__lib__">
  <compilerflag value="-Iinclude"/>
</files>
')
@:native('flite')  # I did try this and the folllowing separately
@:sourceFile('flite/src/synth/flite.c')
@:extern('flite')
extern class Flite {
	
	@:native('flite_init')
	static function flite_init() :Int;

}

I have this error, I would have thought it has to do with the native metatag as it’s warning about scopes.

./src/Main.cpp: In static member function ‘static void Main_obj::main()’:
./src/Main.cpp:29:15: error: ‘flite_init’ was not declared in this scope
 HXDLIN(   5)  flite_init();
               ^~~~~~~~~~
Error: Build failed

I think you need to replace the @:sourceFile with @:headerInclude('flite.h') or @:include('flite.h'), not sure which one.

Thanks :slight_smile: Indeed ! I thought for some reason that that I had the files in the BuildXml, I didn’t need @:include(‘flite.h’) ( and then forgot about it …)

With it I don’t have this error any more .
( Now it still doesn’t work, but for normal c reasons )

I say this but …

val_string, val_int and val_float still seem to cause problems.

obj/linux64/da3c452f_CFFI.o : Dans la fonction « val_string » :
CFFI.cpp:(.text+0x1950) : définitions multiples de « val_string »
obj/linux64/a7ec4624_cst_val.o:cst_val.c:(.text+0x4d0) : défini pour la première fois ici
obj/linux64/da3c452f_CFFI.o : Dans la fonction « val_int » :
CFFI.cpp:(.text+0x1ac0) : définitions multiples de « val_int »
obj/linux64/a7ec4624_cst_val.o:cst_val.c:(.text+0x390) : défini pour la première fois ici
obj/linux64/da3c452f_CFFI.o : Dans la fonction « val_float » :
CFFI.cpp:(.text+0x1b60) : définitions multiples de « val_float »
obj/linux64/a7ec4624_cst_val.o:cst_val.c:(.text+0x430) : défini pour la première fois ici

Hmm in fact if
I put

  <compilerflag value="-Dval_string=vval_string" />
    <compilerflag value="-Dval_int=vval_int" />
    <compilerflag value="-Dval_float=vval_float" />

in the @:BuildXml

I don’t have this error anymore.

I still have problems as the @BuildXml don’t act normal. But I’ll post about it tomorrow.

I’ve reselbed all BuildXml problems. Now I’ll post about/edit my posts later.

I’ll add some links to some interesting tutorials/guides I found
https://wighawag.com/blog/2014/12/hxcpp-externs/

Thanks for the tips of the tests.

Sounds like all solved?

Something to note (that you have probably figured out now) is that @:include('./path') and @:sourceFile('./path') is a path relative to the current haxe file, whereas paths injected into buildXml are relative to the cpp output path (e.g. bin/ or whatever you assigned). Sometimes you need haxe-file relative paths injected into build.xml and currently the best way to do that is via a macro. Here’s an example.

yes:) And all the most important functions have been working ( Now if I want to externalise the whole thing, I’m sure I will encounter some difficulties)

indeed, I’ve noticed the paths weren’t working and I was putting absolute paths for now. Nice trick for the macro. I think I’ll use it.

I had an interesting error, when I used my library with openfl/lime


/home/consonne/Work/Temp/FliteExtension/src/native/flite/include/cst_alloc.h:47:16: error: expected unqualified-id before numeric constant
 #define FALSE (1==0)
                ^
include/lime/media/OpenALAudioContext.h:47:7: note: in expansion of macro ‘FALSE’
   int FALSE;
       ^~~~~

I resolved it with

   <compilerflag value="-DTRUE=TTRUE" />
    <compilerflag value="-DFALSE=FFALSE" />

It feels like cheating. I wonder how you can have your defines separated .

hmm this is an interesting one! I guess #define FALSE is a bit risky but not that uncommon in C libs. Maybe lime could use inline variables there so the word FALSE is never emitted

I can’t see your solution in the post but one solution could be create an intermediate header for your externs and add #undef FALSE after including the flite header (example)

I copy pasted the xml without putting them in preformated text. Corrected now!
Yes, it seems like another interesting way to do it :slight_smile: