Closed Durobot closed 11 months ago
Hm, that's interesting. You're right in that C doesn't support namespaces, but in this case that is "helpful", in that specifying C linkage should cause the compiler/linker to ignore namespaces. Specifically the C++ standard 7.5.6 states that:
Two declarations for a function with C language linkage with the same function name (ignoring the namespace names that qualify it) that appear in different namespace scopes refer to the same function.
...and the example given shows that A::f()
, B::f()
and f()
(where A and B are namespaces) all refer to the same function when C linkage is specified.
That's the basis on which the C header/implementation file here works - it doesn't matter that the header defines ImGui_GetIO()
whilst the CPP file sticks it in a namespace and calls it cimgui::ImGui_GetIO()
, because the extern C
specification should make the linker treat them as the same function.
Which is all a rather tortuous way of saying "that sounds like either a compiler bug or some sort of command-line flags/#define/similar issue". What compiler and settings are you using to compile in this case?
(oh, and don't worry about opening issues! There isn't an official forum or anything, and this sort of thing could easily be either a bug in Dear Bindings or something that whilst "technically" not a bug would be useful to avoid if people are going to run into it on some specific compiler setup, so I'm very happy to see it reported!)
Having gathered all the info for the post below, I have discovered I actually somehow managed to miss cimgui.o
in the linker (gcc
) command. Shame on me for raising a hubbub. It does compile and link, after all. The namespace was a red herring.
My original post follows.
Of course, I should have provided my build environment and script. I'm on Arch Linux:
Linux archvm 6.4.7-arch1-2 #1 SMP PREEMPT_DYNAMIC Mon, 31 Jul 2023 11:41:04 +0000 x86_64 GNU/Linux
Compiler is gcc (GCC) 13.2.1 20230801
.
I'm trying to build the provided example_null.c, renamed to main.c
.
Here's my quick and dirty build script:
#!/bin/sh
BUILD_PATH='./build'
DEAR_BINDINGS_PATH='../../dear_bindings'
IMGUI_PATH="../../imgui"
IMGUI_BACKEND_PATH="${IMGUI_PATH}/backends"
echo "g++ -std=c++11 -I${IMGUI_PATH} -I${IMGUI_BACKEND_PATH} -g -Wall -Wformat `pkg-config --cflags glfw3` -c -o ${BUILD_PATH}/imgui.o ${IMGUI_PATH}/imgui.cpp"
g++ -std=c++11 -I${IMGUI_PATH} -I${IMGUI_BACKEND_PATH} -g -Wall -Wformat `pkg-config --cflags glfw3` -c -o ${BUILD_PATH}/imgui.o ${IMGUI_PATH}/imgui.cpp
echo "g++ -std=c++11 -I${IMGUI_PATH} -I${IMGUI_BACKEND_PATH} -g -Wall -Wformat `pkg-config --cflags glfw3` -c -o ${BUILD_PATH}/imgui_demo.o ${IMGUI_PATH}/imgui_demo.cpp"
g++ -std=c++11 -I${IMGUI_PATH} -I${IMGUI_BACKEND_PATH} -g -Wall -Wformat `pkg-config --cflags glfw3` -c -o ${BUILD_PATH}/imgui_demo.o ${IMGUI_PATH}/imgui_demo.cpp
echo "g++ -std=c++11 -I${IMGUI_PATH} -I${IMGUI_BACKEND_PATH} -g -Wall -Wformat `pkg-config --cflags glfw3` -c -o ${BUILD_PATH}/imgui_draw.o ${IMGUI_PATH}/imgui_draw.cpp"
g++ -std=c++11 -I${IMGUI_PATH} -I${IMGUI_BACKEND_PATH} -g -Wall -Wformat `pkg-config --cflags glfw3` -c -o ${BUILD_PATH}/imgui_draw.o ${IMGUI_PATH}/imgui_draw.cpp
echo "g++ -std=c++11 -I${IMGUI_PATH} -I${IMGUI_BACKEND_PATH} -g -Wall -Wformat `pkg-config --cflags glfw3` -c -o ${BUILD_PATH}/imgui_tables.o ${IMGUI_PATH}/imgui_tables.cpp"
g++ -std=c++11 -I${IMGUI_PATH} -I${IMGUI_BACKEND_PATH} -g -Wall -Wformat `pkg-config --cflags glfw3` -c -o ${BUILD_PATH}/imgui_tables.o ${IMGUI_PATH}/imgui_tables.cpp
echo "g++ -std=c++11 -I${IMGUI_PATH} -I${IMGUI_BACKEND_PATH} -g -Wall -Wformat `pkg-config --cflags glfw3` -c -o ${BUILD_PATH}/imgui_widgets.o ${IMGUI_PATH}/imgui_widgets.cpp"
g++ -std=c++11 -I${IMGUI_PATH} -I${IMGUI_BACKEND_PATH} -g -Wall -Wformat `pkg-config --cflags glfw3` -c -o ${BUILD_PATH}/imgui_widgets.o ${IMGUI_PATH}/imgui_widgets.cpp
echo "g++ -std=c++11 -I${IMGUI_PATH} -I${IMGUI_BACKEND_PATH} -g -Wall -Wformat `pkg-config --cflags glfw3` -c -o ${BUILD_PATH}/imgui_impl_glfw.o ${IMGUI_BACKEND_PATH}/imgui_impl_glfw.cpp"
g++ -std=c++11 -I${IMGUI_PATH} -I${IMGUI_BACKEND_PATH} -g -Wall -Wformat `pkg-config --cflags glfw3` -c -o ${BUILD_PATH}/imgui_impl_glfw.o ${IMGUI_BACKEND_PATH}/imgui_impl_glfw.cpp
echo "g++ -std=c++11 -I${IMGUI_PATH} -I${IMGUI_BACKEND_PATH} -g -Wall -Wformat `pkg-config --cflags glfw3` -c -o ${BUILD_PATH}/imgui_impl_opengl3.o ${IMGUI_BACKEND_PATH}/imgui_impl_opengl3.cpp"
g++ -std=c++11 -I${IMGUI_PATH} -I${IMGUI_BACKEND_PATH} -g -Wall -Wformat `pkg-config --cflags glfw3` -c -o ${BUILD_PATH}/imgui_impl_opengl3.o ${IMGUI_BACKEND_PATH}/imgui_impl_opengl3.cpp
echo "g++ -std=c++11 -DIMGUI_IMPL_API=\"extern \\\"C\\\" \" -I${DEAR_BINDINGS_PATH} -I${IMGUI_PATH} -g -Wall -Wformat -c -o ${BUILD_PATH}/cimgui.o ${DEAR_BINDINGS_PATH}/cimgui.cpp"
g++ -std=c++11 -DIMGUI_IMPL_API="extern \"C\" " -I${DEAR_BINDINGS_PATH} -I${IMGUI_PATH} -g -Wall -Wformat -c -o ${BUILD_PATH}/cimgui.o ${DEAR_BINDINGS_PATH}/cimgui.cpp
echo "gcc -I${DEAR_BINDINGS_PATH} -I${IMGUI_PATH} -g -Wall -Wformat `pkg-config --cflags glfw3` -c -o ${BUILD_PATH}/main.o main.c"
gcc -I${DEAR_BINDINGS_PATH} -I${IMGUI_PATH} -g -Wall -Wformat `pkg-config --cflags glfw3` -c -o ${BUILD_PATH}/main.o main.c
#g++ -o example_glfw_opengl3 main.o imgui.o imgui_demo.o imgui_draw.o imgui_tables.o imgui_widgets.o imgui_impl_glfw.o imgui_impl_opengl3.o -std=c++11 -I${IMGUI_PATH} -I${IMGUI_BACKEND_PATH} -g -Wall -Wformat `pkg-config --cflags glfw3` -lGL `pkg-config --static --libs glfw3`
# -- No difference with gcc below --
#echo "g++ -o ${BUILD_PATH}/dear_bindings_01 ${BUILD_PATH}/main.o ${BUILD_PATH}/imgui.o ${BUILD_PATH}/imgui_demo.o ${BUILD_PATH}/imgui_draw.o ${BUILD_PATH}/imgui_tables.o ${BUILD_PATH}/imgui_widgets.o ${BUILD_PATH}/imgui_impl_glfw.o ${BUILD_PATH}/imgui_impl_opengl3.o -g -Wall -Wformat `pkg-config --cflags glfw3` -lGL `pkg-config --static --libs glfw3`"
#g++ -o ${BUILD_PATH}/dear_bindings_01 ${BUILD_PATH}/main.o ${BUILD_PATH}/imgui.o ${BUILD_PATH}/imgui_demo.o ${BUILD_PATH}/imgui_draw.o ${BUILD_PATH}/imgui_tables.o ${BUILD_PATH}/imgui_widgets.o ${BUILD_PATH}/imgui_impl_glfw.o ${BUILD_PATH}/imgui_impl_opengl3.o -g -Wall -Wformat `pkg-config --cflags glfw3` -lGL `pkg-config --static --libs glfw3`
echo "gcc -o ${BUILD_PATH}/dear_bindings_01 ${BUILD_PATH}/main.o ${BUILD_PATH}/imgui.o ${BUILD_PATH}/imgui_demo.o ${BUILD_PATH}/imgui_draw.o ${BUILD_PATH}/imgui_tables.o ${BUILD_PATH}/imgui_widgets.o ${BUILD_PATH}/imgui_impl_glfw.o ${BUILD_PATH}/imgui_impl_opengl3.o -g -Wall -Wformat `pkg-config --cflags glfw3` -lGL -lstdc++ `pkg-config --static --libs glfw3`"
gcc -o ${BUILD_PATH}/dear_bindings_01 ${BUILD_PATH}/main.o ${BUILD_PATH}/imgui.o ${BUILD_PATH}/imgui_demo.o ${BUILD_PATH}/imgui_draw.o ${BUILD_PATH}/imgui_tables.o ${BUILD_PATH}/imgui_widgets.o ${BUILD_PATH}/imgui_impl_glfw.o ${BUILD_PATH}/imgui_impl_opengl3.o -g -Wall -Wformat `pkg-config --cflags glfw3` -lGL -lstdc++ `pkg-config --static --libs glfw3`
cimgui.h
and cimgui.cpp
are the wrapper generated with dear_bindings
from dear imgui
v1.89.8:
python dear_bindings.py -o cimgui ../imgui/imgui.h
When I run my build script, it compiles everything, but fails at the link step:
./build.sh
g++ -std=c++11 -I../../imgui -I../../imgui/backends -g -Wall -Wformat -c -o ./build/imgui.o ../../imgui/imgui.cpp
g++ -std=c++11 -I../../imgui -I../../imgui/backends -g -Wall -Wformat -c -o ./build/imgui_demo.o ../../imgui/imgui_demo.cpp
g++ -std=c++11 -I../../imgui -I../../imgui/backends -g -Wall -Wformat -c -o ./build/imgui_draw.o ../../imgui/imgui_draw.cpp
g++ -std=c++11 -I../../imgui -I../../imgui/backends -g -Wall -Wformat -c -o ./build/imgui_tables.o ../../imgui/imgui_tables.cpp
g++ -std=c++11 -I../../imgui -I../../imgui/backends -g -Wall -Wformat -c -o ./build/imgui_widgets.o ../../imgui/imgui_widgets.cpp
g++ -std=c++11 -I../../imgui -I../../imgui/backends -g -Wall -Wformat -c -o ./build/imgui_impl_glfw.o ../../imgui/backends/imgui_impl_glfw.cpp
g++ -std=c++11 -I../../imgui -I../../imgui/backends -g -Wall -Wformat -c -o ./build/imgui_impl_opengl3.o ../../imgui/backends/imgui_impl_opengl3.cpp
g++ -std=c++11 -DIMGUI_IMPL_API="extern \"C\" " -I../../dear_bindings -I../../imgui -g -Wall -Wformat -c -o ./build/cimgui.o ../../dear_bindings/cimgui.cpp
gcc -I../../dear_bindings -I../../imgui -g -Wall -Wformat -c -o ./build/main.o main.c
gcc -o ./build/dear_bindings_01 ./build/main.o ./build/imgui.o ./build/imgui_demo.o ./build/imgui_draw.o ./build/imgui_tables.o ./build/imgui_widgets.o ./build/imgui_impl_glfw.o ./build/imgui_impl_opengl3.o -g -Wall -Wformat -lGL -lstdc++ -lglfw -lrt -lm -ldl -lX11 -lpthread -lxcb -lXau -lXdmcp
/usr/bin/ld: ./build/main.o: in function `main':
/home/archie/projects/c-playground/dear_bindings_01/main.c:14:(.text+0x24): undefined reference to `ImGui_CreateContext'
/usr/bin/ld: /home/archie/projects/c-playground/dear_bindings_01/main.c:15:(.text+0x29): undefined reference to `ImGui_GetIO'
/usr/bin/ld: /home/archie/projects/c-playground/dear_bindings_01/main.c:20:(.text+0x57): undefined reference to `ImFontAtlas_GetTexDataAsRGBA32'
/usr/bin/ld: /home/archie/projects/c-playground/dear_bindings_01/main.c:28:(.text+0xb4): undefined reference to `ImGui_NewFrame'
/usr/bin/ld: /home/archie/projects/c-playground/dear_bindings_01/main.c:31:(.text+0xc8): undefined reference to `ImGui_Text'
/usr/bin/ld: /home/archie/projects/c-playground/dear_bindings_01/main.c:32:(.text+0xf3): undefined reference to `ImGui_SliderFloat'
/usr/bin/ld: /home/archie/projects/c-playground/dear_bindings_01/main.c:33:(.text+0x149): undefined reference to `ImGui_Text'
/usr/bin/ld: /home/archie/projects/c-playground/dear_bindings_01/main.c:34:(.text+0x153): undefined reference to `ImGui_ShowDemoWindow'
/usr/bin/ld: /home/archie/projects/c-playground/dear_bindings_01/main.c:36:(.text+0x158): undefined reference to `ImGui_Render'
/usr/bin/ld: /home/archie/projects/c-playground/dear_bindings_01/main.c:40:(.text+0x17f): undefined reference to `ImGui_DestroyContext'
collect2: error: ld returned 1 exit status
(as you can see, I have tried defining IMGUI_IMPL_API
as "extern \"C\" "
when compiling cimgui.cpp
, but that did nothing)
Great, glad you were able to resolve it. We all miss the simple things sometimes!
I'm sorry for opening an issue, it's most probably something I'm missing, but I could not find a discussion forum of any kind for dear_bindings.
While trying to build example_null.c, I'm getting linker errors like these:
I'm certainly not the greatest expert on C++ (to put it mildly), but it does look like the linker has a point here - these functions are declared in
cimgui.h
like this:But their bodies in
cimgui.cpp
are located in a namespace, calledcimgui
:AFAIK, C does not support namespaces (at least, in the same sense as C++ does), so how do I call these functions from C code?