magogware / godot-pdstream

The Godot GDNative library supporting godot-audiostreampd
7 stars 4 forks source link

linux builds #1

Open michal-cab opened 1 year ago

michal-cab commented 1 year ago

hello, in Makefile there is no option for build linux version - i guess this shlould not be problem. I tried to fiddle with Makefile but I ended at error like this:

make -C libpd MULTI=true make[1]: Entering directory '/home/tao/source/godot-pdstream/libpd' make[1]: Nothing to be done for 'libpd'. make[1]: Leaving directory '/home/tao/source/godot-pdstream/libpd' cp libpd/libs/libpd.so bin/libpd.so cc -o bin/libpdstream.so ./src/pdstream.o ./src/instance.o -fPIC -shared -L./libpd/libs -lpd /usr/bin/ld: ./src/pdstream.o: warning: relocation against res_prefix' in read-only section.text' /usr/bin/ld: ./src/pdstream.o: relocation R_X86_64_PC32 against symbol `core_api' can not be used when making a shared object; recompile with -fPIC /usr/bin/ld: final link failed: bad value collect2: error: ld returned 1 exit status make: *** [Makefile:38: bin/libpdstream.so] Error 1

and git submodule update --init --recursive dont work, so i add libpd and pd sources manually

it would be really great to have pdlib api accessible in godot. good work :)

michal-cab commented 1 year ago

great, thnx for makefile! i tried it and i can confirm, that it produces libpdstream.so :)

but when i tried it inside godot (i opened example from godot-audiostream) i got these errors: ERROR: Can't resolve symbol godot_gdnative_init. Error: /home/tao/godot/godot_pd/addons/audiostreampd/lib/linux/libpdstream.so: undefined symbol: godot_gdnative_init. at: get_dynamic_library_symbol_handle (drivers/unix/os_unix.cpp:437) ERROR: Failed to obtain godot_gdnative_init symbol at: initialize (modules/gdnative/gdnative.cpp:372) ERROR: No valid library handle, can't get symbol from GDNative object at: get_symbol (modules/gdnative/gdnative.cpp:510) ERROR: No nativescript_init in "res://addons/audiostreampd/lib/linux/libpdstream.so" found at: init_library (modules/gdnative/nativescript/nativescript.cpp:1503) ERROR: Can't resolve symbol godot_gdnative_init. Error: /home/tao/godot/godot_pd/addons/audiostreampd/lib/linux/libpdstream.so: undefined symbol: godot_gdnative_init. at: get_dynamic_library_symbol_handle (drivers/unix/os_unix.cpp:437) ERROR: Failed to obtain godot_gdnative_init symbol at: initialize (modules/gdnative/gdnative.cpp:372)

after make i got pdstream.o file inside src dir and when i do command " nm pdstream" i got: U add_float
U add_symbol
U bang
0000000000000020 B core_api
U create
U destroy
0000000000000000 B dir_prefix
0000000000000200 T error
U finish_message
U flot
... ... 0000000000001130 T godot_gdnative_init
00000000000011f0 T godot_gdnative_terminate
0000000000000cc0 T godot_nativescript_init
... ... 0000000000000018 B nativescript_api 0000000000000010 B nativescript_ext_api U open U pd_init 0000000000000080 T pdstream_add_float 0000000000000920 T pdstream_add_symbol 0000000000000760 T pdstream_bang 0000000000000000 T pdstream_constructor 0000000000000310 T pdstream_create 0000000000000020 T pdstream_destructor 0000000000000960 T pdstream_finish_message 00000000000006e0 T pdstream_float 0000000000000aa0 T pdstream_open 0000000000000c00 T pdstream_open_args 0000000000000440 T pdstream_perform 00000000000000c0 T pdstream_start_message 00000000000008a0 T pdstream_symbol U perform 0000000000000008 B res_prefix U __stack_chk_fail U start_dsp U start_message U stop_dsp 00000000000009e0 T string_to_chars U strncpy U symbol 0000000000000600 T variant_to_chars

but when i proceed "nm libpdstream.so" i got only: 0000000000004020 b completed.0 w cxa_finalize 0000000000001040 t deregister_tm_clones 00000000000010b0 t __do_global_dtors_aux 0000000000003e88 d do_global_dtors_aux_fini_array_entry 0000000000004018 d dso_handle 0000000000003e90 d _DYNAMIC 00000000000010fc t _fini 00000000000010f0 t frame_dummy 0000000000003e80 d frame_dummy_init_array_entry 0000000000002000 r FRAME_END 0000000000004000 d _GLOBAL_OFFSETTABLE w gmon_start 0000000000001000 t _init w _ITM_deregisterTMCloneTable w _ITM_registerTMCloneTable 0000000000001070 t register_tm_clones 0000000000004020 d __TMC_END__

so my guess there must be something wrong in linking?

opyate commented 1 year ago

Hello, sorry - I deleted the previous Makefile, as it was clearly wrong. I'm getting closer, I guess. Here's my latest one:

SRC = ./src/pdstream.c \
    ./src/instance.c

OUT = bin

INCLUDES = -I./godot-headers \
    -I./libpd/libpd_wrapper \
    -I./libpd/pure-data/src

LIBS = -L./libpd/libs -lpd

CFLAGS = $(INCLUDES)

ifeq ($(shell uname),Darwin)
    SOLIB_PREFIX = lib
    SOLIB_EXT = dylib
else
  ifeq ($(OS), Windows_NT) # Windows, use Mingw
    SOLIB_PREFIX =
    SOLIB_EXT = dll
    LDFLAGS += -Wl,--export-all-symbols \
      -static-libgcc
  else # assume Linux
    SOLIB_PREFIX = lib
    SOLIB_EXT = so
  endif
endif

LDFLAGS += -shared\
    $(LIBS)

ifeq ($(shell uname),Linux)
  CFLAGS += -fPIC
endif

PDSTREAM = $(OUT)/$(SOLIB_PREFIX)pdstream.$(SOLIB_EXT)

LIBPD_DIR = libpd
LIBPD_FLAGS = MULTI=true
LIBPD = $(LIBPD_DIR)/libs/$(SOLIB_PREFIX)pd.$(SOLIB_EXT)
LIBPD_LOCAL = $(OUT)/$(SOLIB_PREFIX)pd.$(SOLIB_EXT)

ifeq ($(OS),Windows_NT)
    LIBPD_FLAGS += ADDITIONAL_CFLAGS='-DPD_LONGINTTYPE="long long"'
endif

$(PDSTREAM): ${SRC:.c=.o} $(LIBPD_LOCAL)
    $(CC) -o $@ $(CFLAGS) ${SRC:.c=.o} $(LDFLAGS)

$(LIBPD_LOCAL): Makefile.patch $(OUT)
ifeq ($(OS),Windows_NT)
    patch -u $(LIBPD_DIR)/Makefile $<
endif
    $(MAKE) -C $(LIBPD_DIR) $(LIBPD_FLAGS)
    cp $(LIBPD) $@

$(OUT):
    mkdir $@

clean:
    rm ${SRC:.c=.o}
    rm $(PDSTREAM)

But there are still linking issues.

image

Inside Godot:

E 0:00:00.384   open_dynamic_library: Can't open dynamic library: /home/opyate/the-game/addons/audiostreampd/lib/linux/libpdstream.so. Error: libpd.so: cannot open shared object file: No such file or directory
opyate commented 1 year ago

Here's nm using my latest Makefile:

nm bin/libpdstream.so  
0000000000003ee7 T add_float
0000000000003f1a T add_symbol
0000000000004017 T bang
0000000000003dc7 T close
0000000000007148 b completed.0
0000000000007150 B core_api
0000000000003c53 T create
                 w __cxa_finalize@GLIBC_2.2.5
00000000000024e0 t deregister_tm_clones
0000000000003d0b T destroy
0000000000007170 B dir_prefix
0000000000002550 t __do_global_dtors_aux
0000000000006d80 d __do_global_dtors_aux_fini_array_entry
0000000000007140 d __dso_handle
0000000000006d88 d _DYNAMIC
0000000000002599 T error
0000000000004148 t _fini
0000000000003f4c T finish_list
0000000000003fcb T finish_message
0000000000004058 T flot
0000000000002590 t frame_dummy
0000000000006d78 d __frame_dummy_init_array_entry
00000000000058a0 r __FRAME_END__
0000000000005260 r __func__.0
0000000000005240 r __func__.1
0000000000005220 r __func__.2
0000000000005210 r __func__.3
00000000000051f8 r __func__.4
00000000000051e0 r __func__.5
00000000000051d0 r __func__.6
00000000000051c0 r __func__.7
0000000000007000 d _GLOBAL_OFFSET_TABLE_
                 w __gmon_start__
000000000000528c r __GNU_EH_FRAME_HDR
0000000000003af3 T godot_gdnative_init
0000000000003c0b T godot_gdnative_terminate
0000000000003533 T godot_nativescript_init
0000000000002000 t _init
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
                 U libpd_add_float
                 U libpd_add_symbol
                 U libpd_bang
                 U libpd_closefile
                 U libpd_finish_list
                 U libpd_finish_message
                 U libpd_float
                 U libpd_free_instance
                 U libpd_init
                 U libpd_init_audio
                 U libpd_new_instance
                 U libpd_openfile
                 U libpd_process_float
                 U libpd_set_instance
                 U libpd_start_message
                 U libpd_symbol
0000000000007158 B nativescript_api
0000000000007160 B nativescript_ext_api
0000000000003d48 T open
0000000000003c44 T pd_init
0000000000003318 T pdstream_add_float
0000000000003384 T pdstream_add_symbol
00000000000031cd T pdstream_bang
000000000000297c T pdstream_constructor
0000000000002a69 T pdstream_create
00000000000029b2 T pdstream_destructor
0000000000003473 T pdstream_finish_message
0000000000003111 T pdstream_float
0000000000002bf3 T pdstream_open
0000000000002dc3 T pdstream_open_args
0000000000002ebd T pdstream_perform
00000000000033f7 T pdstream_start_message
0000000000003258 T pdstream_symbol
00000000000040f1 T perform
0000000000002510 t register_tm_clones
0000000000007168 B res_prefix
                 U __stack_chk_fail@GLIBC_2.4
0000000000003e0b T start_dsp
0000000000003f8d T start_message
0000000000003e79 T stop_dsp
0000000000002885 T string_to_chars
                 U strncpy@GLIBC_2.2.5
00000000000040a5 T symbol
0000000000007148 d __TMC_END__
0000000000002756 T variant_to_chars
opyate commented 1 year ago

More information: I'm using more recent versions of libpd and puredata:

cd libpd/pure-data
git checkout 0.53-1

And

cd libpd
git checkout 0.13.2
michal-cab commented 1 year ago

yep i can just confirm that error concerning loading libpd :-o: (ofcourse i added it to deps inside PdStream.tres)

ERROR: Can't open dynamic library: /home/tao/godot/godot_pd/addons/audiostreampd/lib/linux/libpdstream.so. Error: libpd.so: cannot open shared object file: No such file or directory at: open_dynamic_library (drivers/unix/os_unix.cpp:418) ERROR: No valid library handle, can't get symbol from GDNative object at: get_symbol (modules/gdnative/gdnative.cpp:510) ERROR: No nativescript_init in "res://addons/audiostreampd/lib/linux/libpdstream.so" found at: init_library (modules/gdnative/nativescript/nativescript.cpp:1503) ERROR: No valid library handle, can't get symbol from GDNative object at: get_symbol (modules/gdnative/gdnative.cpp:510) ERROR: No valid library handle, can't terminate GDNative object at: terminate (modules/gdnative/gdnative.cpp:417) ERROR: Can't open dynamic library: /home/tao/godot/godot_pd/addons/audiostreampd/lib/linux/libpdstream.so. Error: libpd.so: cannot open shared object file: No such file or directory at: open_dynamic_library (drivers/unix/os_unix.cpp:418)

huh thats strange :/

opyate commented 1 year ago

~I'll try and compile a combined .so file for both.~

Wait, before I go down a rabbit hole...

It's linked properly:

$ ls
libpd.so  libpdstream.so
$ LD_LIBRARY_PATH=. ldd libpdstream.so
    linux-vdso.so.1 (0x00007ffc770fa000)
    libpd.so => ./libpd.so (0x00007fcdc4e58000)                   // <---- here it is!
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fcdc4c15000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fcdc4b2e000)
    libmvec.so.1 => /lib/x86_64-linux-gnu/libmvec.so.1 (0x00007fcdc4a31000)
    /lib64/ld-linux-x86-64.so.2 (0x00007fcdc4fe9000)

I'll try this rpath trick: https://github.com/godotengine/godot/issues/20765

opyate commented 1 year ago

OK, no more errors from Godot, but running GUI.tscn just exits the scene 🤔

Here's the latest Makefile:

        SOLIB_PREFIX = lib
        SOLIB_EXT = dylib
 else
-       SOLIB_PREFIX =
-       SOLIB_EXT = dll
-       LDFLAGS += -Wl,--export-all-symbols \
-               -static-libgcc
+  ifeq ($(OS), Windows_NT) # Windows, use Mingw
+    SOLIB_PREFIX =
+    SOLIB_EXT = dll
+    LDFLAGS += -Wl,--export-all-symbols \
+      -static-libgcc
+  else # assume Linux
+    SOLIB_PREFIX = lib
+    SOLIB_EXT = so
+  endif
 endif

 LDFLAGS += -shared\
        $(LIBS)

+ifeq ($(shell uname),Linux)
+  CFLAGS += -fPIC
+  LDFLAGS += '-Wl,-rpath,addons/audiostreampd/lib/linux'
+endif
+
 PDSTREAM = $(OUT)/$(SOLIB_PREFIX)pdstream.$(SOLIB_EXT)

 LIBPD_DIR = libpd
@@ -36,7 +46,7 @@ ifeq ($(OS),Windows_NT)
 endif

 $(PDSTREAM): ${SRC:.c=.o} $(LIBPD_LOCAL)
-       $(CC) -o $@ ${SRC:.c=.o} $(LDFLAGS)
+       $(CC) -o $@ $(CFLAGS) ${SRC:.c=.o} $(LDFLAGS)

 $(LIBPD_LOCAL): Makefile.patch $(OUT)
 ifeq ($(OS),Windows_NT)
opyate commented 1 year ago

OK, I got it to work when I remove the error handler, i.e.

// error(pd_init(), __func__, __LINE__);
pd_init(); // just call this

I'm trying to figure out if anything broke when going to tag 0.13.2 in libpd, as I'd like to keep the error handler and not let rogue PD crash the game.

It seems as through this repo points to a libpd from 2021-11-19, but:

So it's somewhere in-between these two stable tags.

Looking at the changelog now...

magogware commented 1 year ago

Thank you all so much for your work. I apologise that a Linux build wasn't included to begin with; I lost access to a Linux machine last year and never got around to testing anything on Linux after moving to a Mac. My guess would have been, having dealt with build issues when creating the Windows and Mac Makefiles, that either the library or some of its dependencies are not being located correctly or are a mismatched architecture.

From the looks of things, though, @opyate has a working Make recipe. I don't believe libpd has introduced any breaking API changes, as I used libpd in some other projects with similar code to this repo. @opyate, if you could confirm your fix and submit a pull request with your Makefile and submodule changes, I'll merge it in.

Again, thank you all for your work and sorry for the radio silence.

opyate commented 1 year ago

@magogware no worries :)

Found the reason why the TSCN (the game) just exits. The error handler is clashing with some other function called error (it's quite a generic function name, which might work better from behind a namespace), so this works:

s/ error\(/ error_reporter\(/g

I'll open a PR for this.

magogware commented 1 year ago

Brilliant sleuthing! Out of curiosity, any indication what function is clashing? I took a brief look through z_libpd.c and m_pd.c and couldn't find anything, but it could be something within string.h.

opyate commented 1 year ago

When I rename this error function to anything else, like error_reporter, then the plugin runs without exiting:

https://github.com/magogware/godot-pdstream/blob/master/src/pdstream.c#L12

EDIT: ok, it just occurs to me that you're asking about what function not written by yourself might be clashing :) No idea - all I know is that the rename fixes things, so I just presume there's an error() function elsewhere in maybe godot-headers or libpd.

michal-cab commented 1 year ago

slowly getting there but something strange is also happening... :/ i did: git clone https://github.com/opyate/godot-pdstream.git git checkout fixes-for-linux git submodule update --init --recursive

make went just fine producing libpd.so and libpdstream.so.

i created new project in godot 3.5.1 copied addons dir from godot-audiostream into it, also copied compiled libpd.so and libpdstream.so into ../lib/linux dir and set paths in PdStream.tres . saved that project and when i try to open and run it from godot editor it spills warnings (which are not essential i guess): WARNING: Error setting locale modifiers
at: initialize (platform/x11/os_x11.cpp:166)
WARNING: XOpenIM failed
at: initialize (platform/x11/os_x11.cpp:213)
WARNING: XCreateIC couldn't create xic
at: initialize (platform/x11/os_x11.cpp:510)
i guess libpd was opened also just fine as in terminal i can see: [~]$ pd 0.53.1
bonk version 1.5
fiddle version 1.1 TEST4
pd~ version 0.54
pique 0.1 for PD version 23
sigmund~ version 0.07
pd 0.53.1
bonk version 1.5
fiddle version 1.1 TEST4
pd~ version 0.54
pique 0.1 for PD version 23
sigmund~ version 0.07
pd 0.53.1
bonk version 1.5
fiddle version 1.1 TEST4
pd~ version 0.54
pique 0.1 for PD version 23
sigmund~ version 0.07
pd 0.53.1
bonk version 1.5
fiddle version 1.1 TEST4
pd~ version 0.54
pique 0.1 for PD version 23

it even creates window without those four buttons and spills errors like: SCRIPT ERROR: Invalid call. Nonexistent function 'open' in base 'Reference (PdStream.gdns)'.
at: AudioStreamPd.setup (res://addons/audiostreampd/AudioStreamPd.gd:15)
SCRIPT ERROR: Invalid call. Nonexistent function 'flot' in base 'Reference (PdStream.gdns)'.
at: AudioStreamPd.flot (res://addons/audiostreampd/AudioStreamPd.gd:45)
SCRIPT ERROR: Invalid call. Nonexistent function 'connect' in base 'Nil'.
at: _ready (res://addons/audiostreampd/example/GUI.gd:10)
ERROR: Parameter "p_child" is null. at: add_child (scene/main/node.cpp:1280)

in Pdstream.gdns is just this: [gd_resource type="NativeScript" load_steps=2 format=2]

[ext_resource path="res://addons/audiostreampd/PdStream.tres" type="GDNativeLibrary" id=1]

[resource]
class_name = "PdStream"
library = ExtResource( 1 )
script_class_name = "PdStream"

on line 15 in AudioStreamPd.gd is pdstream.open(patch) so it has a problem to open source pd file? but when i tried to print var patch it just points to: res://addons/audiostreampd/example/sawtooth.pd

maybe i am doing some stupid error but have no idea what i am doing wrong :/. ev. will be thankful for advice. just to add that i am on ubuntu 22.04.1 LTS

opyate commented 1 year ago

@michal-cab

I see this error too, but can make it go away if I set a breakpoint on PdStream.new() in the gdscript:

SCRIPT ERROR: Invalid call. Nonexistent function 'open' in base 'Reference (PdStream.gdns)'.
at: AudioStreamPd.setup (res://addons/audiostreampd/AudioStreamPd.gd:15)

Then I just step over the next to lines manually.

func setup(player_node: Node):
    pdstream = PdStream.new()  # <--- set break point here
    pdstream.create()                   # <--- step
    pdstream.open(patch)            # <--- step

It looks like a race condition. I'm looking at a way to slow the initialisation down.

As for the second error:

SCRIPT ERROR: Invalid call. Nonexistent function 'flot' in base 'Reference (PdStream.gdns)'.
at: AudioStreamPd.flot (res://addons/audiostreampd/AudioStreamPd.gd:45)

I'm also seeing this, and working on it now. I suppose both of these are a new issue, as the original issue has now been answered (builds on Linux)?

opyate commented 1 year ago

I got it to work. Perhaps crucially because I renamed open to something else to prevent name clashes.

https://github.com/opyate/godot-pdstream/commit/a771d1afe88e162f56443a35d0231911f18d0df9

There was an open in src/instance.(c|h) and also defined as godot_instance_method open inside godot_nativescript_init which might have clobbered the definition in src/instance.(c|h)

Screencast: https://youtu.be/fIjNBv-tS5Q (HD should be ready 30 minutes from time of writing this)

¯\_(ツ)_/¯

PS I just stumbled upon this solution thanks to gdb. I wanted to set a breakpoint on open to see what happens, but if you do that, it stops almost everywhere in the stack, as a LOT of methods are called open. So, I gave it a unique name, and the thing started working magically 🤣

michal-cab commented 1 year ago

(yep it looks like progress, thnx! :) can confirm that with breakpoints it works, but without them nope...)

michal-cab commented 1 year ago

hallo, any chance to merge opyate tribute, or to make it work under godot4? as we have stable version already...