How to interface to C++ from D correctly? - c++

I tried to inteface between C++ and D.
The problem is that I can't compile it. I used the code/command line on the website
> g++ -c foo.cpp
> dmd bar.d foo.o -L-lstdc++ && ./bar
and it didn't work: first of all the DMD compiler doesn't use .o files so i had to specify manually to create a .obj file then the linker threw an error because it didn't knew /lstdc++ so i configured the cpp libs manually.
Thats the point where i am now it throws an "Symbol not found" error and i don't know how to fix this, am i doing something wrong on compiling? or is it on the programming site?
here my compile commands:
PS C:\Users\kunde\Downloads\d-interface test> g++ -c -o test-cpp.obj test.cpp
PS C:\Users\kunde\Downloads\d-interface test> dmd -L"G:\GNUstep\lib\gcc\mingw32\4.6.1\libstdc++.dll.a" -L"G:\GNUstep\lib\gcc\mingw32\4.6.1\libstdc++.a" .\test-cpp.obj .\test.d
test.obj : error LNK2019: Verweis auf nicht aufgelöstes externes Symbol ""char __cdecl foo(int)" (?foo##YADH#Z)" in Funktion "__Dmain".
test-cpp.exe : fatal error LNK1120: 1 nicht aufgelöste Externe
Error: linker exited with status 1120
and my code:
test.d:
import std.stdio;
extern (C++) char foo(int i);
void main(string[] args)
{
writefln("%c", foo(14));
}
test.cpp:
#include <iostream>
extern "C" {
#include "test.h"
}
char foo(int i){
std::cout << "got: ";
return (char)bar(i);
}
and test.h:
#include <stdio.h>
int bar(int a){
printf("returned %d", a*a);
return a*a;
}
What am I doing wrong?
P.s.: im german so the errors may have to be translated
Edit: As sayd in the answers MSVC fixed the problem i changed "g++ -c -o test-cpp.obj test.cpp" to "cl test.cpp -c /EHsc"

C++ is a finicky beast - its name mangling details are implementation defined, so it varies by platform and compiler. dmd picks one it considers the main compiler on the system and copies it. On Linux, that's g++.... but on Windows, it is Microsoft C++, not g++.
So you have to use a matching compiler. On Windows, there is the gdc compiler - a D compiler built into gcc - but there's no binary builds for it available at this time. You'd have to compile it yourself with some config flags...
../gcc/configure --prefix=/mingw64 --host=x86_64-w64-mingw32 --build=x86_64-w64-mingw32 --target=x86_64-w64-mingw32 --disable-bootstrap --disable-werror --disable-libssp --disable-libgomp --disable-libmudflap --disable-libquadmath --disable-libitm --disable-libsanitizer --disable-libstdcxx-pch --with-arch=x86-64 --with-gnu-as --with-gnu-ld --with-gmp=/mingw64 --with-mpfr=/mingw64 --with-mpc=/mingw64 --with-isl=/mingw64 --with-native-system-header-dir=/mingw64/x86_64-w64-mingw32/include --libexecdir=/mingw64/lib --enable-languages=d --enable-libphobos --enable-shared --enable-static --disable-multilib
is what I used.
It is a bit of a pain. I've never actually tested the extern(C++) on gdc/Windows either.
So I'd suggest either using the MSVC compiler on the C++ together with dmd.... or probably better yet making the interface extern(C) instead. The C interface is far more compatible across things.
And the .o vs .obj thing is the same case - gcc uses .o, dmd and msvc use .obj (at least -m64 bit builds match, 32 bit is more complicated depending on version number)... so really using the same compiler family is going to get you best results.

Related

LLD undefined symbol when attempting to link glfw

I've been trying to get an LLVM toolchain setup on my Windows 10 machine. I gave up on building from source and have the MSYS2 mingw-w64-clang-x86_64-toolchain package installed (clang version 13.0.0).
I can compile simple code that uses the C++ standard library. I'm using clang to compile, lld to link, and I should be using libc++.
To test linking an additional library, I'm using glfw:
#include <iostream>
#include <vector>
#include "glfw3.h"
int main(int argc, char **argv) {
glfwInit();
std::vector<int> testVector = {4, 5, 6, 7, 2};
testVector.push_back(23);
std::cout << testVector[1] << std::endl;
return 0;
}
This compiles and runs fine if I comment out the glfwInit(); line and use this command :
clang++ -Iinclude\ -Llib\ -lglfw3 -v .\main.cpp
So it seems lld is finding the libglfw3.a library file I placed in the lib\ directory.
But if glfwInit(); is uncommented, with the same command I get a lot of unresolved symbol errors:
ld.lld: error: undefined symbol: __declspec(dllimport) CreateDIBSection
>>> referenced by libglfw3.a(win32_window.c.obj):(createIcon)
ld.lld: error: undefined symbol: __declspec(dllimport) CreateBitmap
>>> referenced by libglfw3.a(win32_window.c.obj):(createIcon)
ld.lld: error: undefined symbol: __declspec(dllimport) DeleteObject
>>> referenced by libglfw3.a(win32_window.c.obj):(createIcon)
>>> referenced by libglfw3.a(win32_window.c.obj):(createIcon)
>>> referenced by libglfw3.a(win32_window.c.obj):(updateFramebufferTransparency)
..and so on.
I built the glfw library from the glfw source code using CMake, Ninja, and Clang.
The win32_window.c.obj file and all others referenced by these errors are a couple directories deeper in the lib\ directory, but I can't seem to get clang/lld to find them.
What argument am I missing here?
Edit: I ran this
clang++ -### -Iinclude\ -Llib\ -lglfw3 -v .\main.cpp
And got these two lines:
"C:/msys64/clang64/bin/clang++.exe" "-cc1" "-triple" "x86_64-w64-windows-gnu" "-emit-obj" "-mrelax-all" "--mrelax-relocations" "-disable-free"
"-disable-llvm-verifier" "-discard-value-names" "-main-file-name" "main.cpp" "-mrelocation-model" "pic" "-pic-level" "2" "-mframe-pointer=none"
"-fmath-errno" "-fno-rounding-math" "-mconstructor-aliases" "-mms-bitfields" "-munwind-tables" "-target-cpu" "x86-64" "-tune-cpu" "generic"
"-debugger-tuning=gdb" "-v" "-fcoverage-compilation-dir=C:\\Users\\gcvan\\testProgram" "-resource-dir" "C:/msys64/clang64/lib/clang/13.0.0"
"-I" "include\\" "-internal-isystem" "C:/msys64/clang64/x86_64-w64-mingw32/include/c++/v1" "-internal-isystem" "C:/msys64/clang64/include/c++/v1"
"-internal-isystem" "C:/msys64/clang64/lib/clang/13.0.0/include" "-internal-isystem" "C:/msys64/clang64/x86_64-w64-mingw32/include"
"-internal-isystem" "C:/msys64/clang64/include" "-fdeprecated-macro" "-fdebug-compilation-dir=C:\\Users\\gcvan\\testProgram" "-ferror-limit"
"19" "-fmessage-length=120" "-fno-use-cxa-atexit" "-fgnuc-version=4.2.1" "-fcxx-exceptions" "-fexceptions" "-exception-model=seh"
"-fcolor-diagnostics" "-faddrsig" "-o" "C:/Users/gcvan/AppData/Local/Temp/main-c1d43f.o" "-x" "c++" ".\\main.cpp"
"C:/msys64/clang64/bin/ld.lld" "-m" "i386pep" "-Bdynamic" "-o" "a.exe" "C:/msys64/clang64/x86_64-w64-mingw32/lib/crt2.o"
"C:/msys64/clang64/x86_64-w64-mingw32/lib/crtbegin.o" "-Llib\\" "-LC:/msys64/clang64/x86_64-w64-mingw32/lib" "-LC:/msys64/clang64/lib"
"-LC:/msys64/clang64/x86_64-w64-mingw32/sys-root/mingw/lib" "-LC:/msys64/clang64/lib/clang/13.0.0/lib/windows" "-LC:\\cppLibraries" "-lglfw3"
"C:/Users/gcvan/AppData/Local/Temp/main-c1d43f.o" "-lc++" "-lmingw32" "C:/msys64/clang64/lib/clang/13.0.0/lib/windows/libclang_rt.builtins-x86_64.a"
"-lunwind" "-lmoldname" "-lmingwex" "-lmsvcrt" "-ladvapi32" "-lshell32" "-luser32" "-lkernel32" "-lmingw32"
"C:/msys64/clang64/lib/clang/13.0.0/lib/windows/libclang_rt.builtins-x86_64.a" "-lunwind" "-lmoldname" "-lmingwex" "-lmsvcrt" "-lkernel32"
"C:/msys64/clang64/x86_64-w64-mingw32/lib/crtend.o"
Well, it seems I have a lot to learn about command line compiling/linking.
I fixed it by adding -lgdi32 to the compile tags:
clang++ -Iinclude\ -Llib\ -lglfw3 -lgdi32 -v .\main.cpp
Got the idea from this thread: https://github.com/ziglang/zig/issues/3319
From the thread, near the bottom, there is some good advice:
When you see undefined symbol: __imp_CreateDCW the trick is to look up what DLL that is in. A duck duck go search lands us at https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-createdcw which says at the bottom it is in Gdi32.dll. So you need addSystemLibrary("Gdi32").
For some reason I assumed all the undefined function calls were from glfw, but they aren't, they are from the GDI32 Win32 library.
Just goes to show, for anyone at my experience level, you should probably make sure to google ALL relevant text from your errors and don't make assumptions about the provenance of things..

Using Clang on Windows 10 with LLD

Compiling a simple hello world program generates warnings when compiling with clang. I understand that using clang-cl will get rid of the warnings.
On Clang's website, it states: "clang-cl is an alternative command-line interface to Clang, designed for compatibility with the Visual C++ compiler, cl.exe."
I do not want to use Microsoft Visual C++'s tool chain. I want to use Clang as the compiler and LLD as the linker.
What is meant by "compatibility with the Visual C++ compiler"?
How do I know which linker is used by default? Clang's documentation says that LLD is used by default, but, if so, then why is there a warning? And why is clang-cl the recommended solution for this warning?
clang
I compiled:
clang main.cpp
and got warnings:
main-a354e7.o : warning LNK4217: locally defined symbol _CxxThrowException imported in function "class std::num_put<char,class std::ostreambuf_iterator<char,struct std::char_traits<char> > > const & __cdecl std::use_facet<class std::num_put<char,class std::ostreambuf_iterator<char,struct std::char_traits<char> > > >(class std::locale const &)" (??$use_facet#V?$num_put#DV?$ostreambuf_iterator#DU?$char_traits#D#std###std###std###std##YAAEBV?$num_put#DV?$ostreambuf_iterator#DU?$char_traits#D#std###std###0#AEBVlocale#0##Z)
main-a354e7.o : warning LNK4217: locally defined symbol __std_terminate imported in function "int `public: __cdecl std::locale::~locale(void)'::`1'::dtor$6" (?dtor$6#?0???1locale#std##QEAA#XZ#4HA)
It still generated an a.exe file. However, this same command generates no file when run in a Debian terminal (WSL Windows Subsystem for Linux) and has errors.
clang && lld [lld-link]
I tried compiling to object code and then passing this to LLD. It resulted in an error:
clang -c main.cpp -o main.o
lld-link main.o
lld-link: error: could not open libcpmt.lib: no such file or directory
What is this library? Where did it come from? Why is it not found?
main.cpp
#include <iostream>
using namespace std;
int add1(int x);
int main()
{
int a;
a = 1;
cout << a << endl; //prints a and goes to new line
a = add1(a);
return 0; //must return 0 to tell the OS the
//program executed successfully
}
int add1( int x )
{
x = x + 1;
return x;
}
clang is the C compiler, clang++ is the c++ one. So to compile as c++, you need clang -c main.cpp -o main.o
clang-cl on the other end is an alternative driver. If you don't want to use the toolchain, don't bother about it. However, if you are like me and try to compile a project that currently compiles with MSVC and want to also compile it with clang, it's really useful.
The main difference, if you don't play with triples is the platform ABI it links to.
Clang++ links against the mingw standard library while clang-cl uses the Microsoft runtime. As a consequence, the name mangling ... is also MSVC compatible. (Of, and it has a permissive mode in which it allows some invalid code for compatibility)

Missing CoTaskMemFree when building LLVM example on Windows

I'm attempting to essentially follow the llvm Kaleidoscope example.
I'm on Windows. I built llvm from source per the directions on the site. It took quite a long time but it finally built successfully (no errors at least).
Then with my own code I am running this command:
$ clang-cl main.obj llvm/lib/LLVMCore.lib llvm/lib/LLVMSupport.lib /MDd -o build\test.exe
My main.cpp code has this in it:
#include "llvm/ADT/STLExtras.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"
std::unique_ptr<Module> module = llvm::make_unique<Module>("my cool jit", getGlobalContext());
And I'm not getting any parser errors but I am getting an error from the linker that for the life of me I cannot figure out:
LLVMSupport.lib(Path.obj) : error LNK2019: unresolved external symbol
__imp_CoTaskMemFree referenced in function "bool __cdecl
llvm::sys::path::getKnownFolderPath(struct _GUID,class
llvm::SmallVectorImpl<char> &)" (?
getKnownFolderPath#path#sys#llvm##YA_NU_GUID##AEAV?$SmallVectorImpl#D#3##Z)
build\test.exe : fatal error LNK1120: 1 unresolved externals
Which library do I have to link to for this function to be defined? I can see the implementation in the code I built from. Do I need to build llvm in a particular way for this to be exported?
EDIT:
It turns out that I needed to read the clang-cl documentation a little better where it says:
To enable clang-cl to find system headers, libraries, and the linker when run from the command-line, it should be executed inside a Visual Studio Native Tools Command Prompt or a regular Command Prompt where the environment has been set up using e.g. vcvars32.bat.
It turns out that this solves my problem. I was a little confused because clang-cl seems to resolve the sdk include and tool paths automatically, but not the lib paths. I also don't want to use CMD to drive clang so I was using bash where I can't run vcvar32.bat easily. I solved my problem by essentially duplicating what vcvar32.bat is doing to the $PATH, $INCLUDE, $LIB and $LIBPATH environment variables and adding Ole32.Lib as a parameter to clang-cl. It then works like a charm.
You're missing the CoTaskMemFree symbol. A quick look on the Internet suggests you'll need the Ole32 system library on your link line.
I don't have access to a Windows machine to test on, but on my computer, I can run llvm-config --system-libs and it pulls in the all the necessary things. After adding using namespace llvm; and adding a stub main function, I can easily build this example with (on OSX):
c++ `llvm-config --cxxflags` main.cpp `llvm-config --ldflags --system-libs --libs core support`
I often recommend just specifying --libs rather than guessing what you'll need, but your choice.

Building C++ file with g++ in Windows not working as .bat

Good morning,
I am a new user of Windows (+10 years using Linux) and for some reason I have to compile a C++ program. I do not have a big experience in debugging in Windows, but I am eager to understand what I do wrong.
I use MinGW with g++ and different libraries, particularly one called libjpeg.
When I compile & build the file in a PowerShell using the following command, everything works fine, and my C++ code gives me the expected results.
g++ -o imageProcessing imageProcessing.cpp -lgdi32 -Dgmic_use_jpeg -I'C:\GnuWin32\include' -L'C:\GnuWin32\lib' -ljpeg
When I use the exact same command in a .bat file, or directly in my C++ editor (geany), I have this error:
imageProcessing.cpp:6:21: fatal error: jpeglib.h: No such file or directory
#include <jpeglib.h>
^
compilation terminated.
It doesn't find the jpeglib.h.
The correct path were set in the environmental variables.
The libjpeg I use allows me to open/save jpeg pictures when I use the CImg library. It can be found here:
Jpeg for Windows
Here is a very simple example:
#include <iostream>
#include <jpeglib.h>
using namespace std;
int main() {
float number;
cout << "Enter a number: ";
cin >> number;
}
Let's call this test.cpp and its location is: C:\Users\Rémi\Documents\Image_Procesing\C++\testCImg
Here is what I've added in my environmental variables path: C:\GnuWin32\lib;C:\GnuWin32\bin;C:\MinGW\bin;
Here is my test.bat: g++ -o test test.cpp -lgdi32 -Dgmic_use_jpeg -I'C:\GnuWin32\include' -L'C:\GnuWin32\lib' -ljpeg
test.bat is also located in: C:\Users\Rémi\Documents\Image_Procesing\C++\testCImg
the .bat fail is the following:
C:\Users\Rémi\Documents\Image_Procesing\C++\testCImg>g++ -o test test.cpp -lgdi32 -Dgmic_use_jpeg -I'C:\GnuWin32\include
' -L'C:\GnuWin32\lib' -ljpeg
test.cpp:3:21: fatal error: jpeglib.h: No such file or directory
#include <jpeglib.h>
^
compilation terminated.
I spent all my day yesterday trying to figure it out, and I am limited by my Windows knowledge.
If someone could help me, I would appreciate it very much.
Thank you.
When you have include path problems, ask GCC to tell you what it's using.
In the below example, you can clearly see that it's searching for a location 'test' and ignoring it for not existing.
You can then deduce that, as mentioned elsewhere, the single quotes are wrong in Batch. At that point you'd give "test" a go and achieve success.
Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation. All rights reserved.
C:\Users\lightness>g++ -E -x c++ - -v -I'test'
Using built-in specs.
COLLECT_GCC=g++
Target: mingw32
Configured with: ../../src/gcc-4.7.1/configure --build=mingw32 --enable-language
s=c,c++,ada,fortran,objc,obj-c++ --enable-threads=win32 --enable-libgomp --enabl
e-lto --enable-fully-dynamic-string --enable-libstdcxx-debug --enable-version-sp
ecific-runtime-libs --with-gnu-ld --disable-nls --disable-win32-registry --disab
le-symvers --disable-build-poststage1-with-cxx --disable-werror --prefix=/mingw3
2tdm --with-local-prefix=/mingw32tdm --enable-cxx-flags='-fno-function-sections
-fno-data-sections' --with-pkgversion=tdm-1 --enable-sjlj-exceptions --with-bugu
rl=http://tdm-gcc.tdragon.net/bugs
Thread model: win32
gcc version 4.7.1 (tdm-1)
COLLECT_GCC_OPTIONS='-E' '-v' '-I' ''\''test'\''' '-mtune=i386' '-march=i386'
c:/mingw32/bin/../libexec/gcc/mingw32/4.7.1/cc1plus.exe -E -quiet -v -I 'test'
-iprefix c:\mingw32\bin\../lib/gcc/mingw32/4.7.1/ - -mtune=i386 -march=i386
ignoring nonexistent directory "c:\mingw32\bin\../lib/gcc/mingw32/4.7.1/../../..
/../mingw32/include"
ignoring duplicate directory "c:/mingw32/lib/gcc/../../lib/gcc/mingw32/4.7.1/inc
lude/c++"
ignoring duplicate directory "c:/mingw32/lib/gcc/../../lib/gcc/mingw32/4.7.1/inc
lude/c++/mingw32"
ignoring duplicate directory "c:/mingw32/lib/gcc/../../lib/gcc/mingw32/4.7.1/inc
lude/c++/backward"
ignoring duplicate directory "c:/mingw32/lib/gcc/../../lib/gcc/mingw32/4.7.1/inc
lude"
ignoring duplicate directory "c:/mingw32/lib/gcc/../../lib/gcc/mingw32/4.7.1/../
../../../include"
ignoring duplicate directory "c:/mingw32/lib/gcc/../../lib/gcc/mingw32/4.7.1/inc
lude-fixed"
ignoring nonexistent directory "c:/mingw32/lib/gcc/../../lib/gcc/mingw32/4.7.1/.
./../../../mingw32/include"
ignoring nonexistent directory "'test'"
#include "..." search starts here:
#include <...> search starts here:
c:\mingw32\bin\../lib/gcc/mingw32/4.7.1/include/c++
c:\mingw32\bin\../lib/gcc/mingw32/4.7.1/include/c++/mingw32
c:\mingw32\bin\../lib/gcc/mingw32/4.7.1/include/c++/backward
c:\mingw32\bin\../lib/gcc/mingw32/4.7.1/include
c:\mingw32\bin\../lib/gcc/mingw32/4.7.1/../../../../include
c:\mingw32\bin\../lib/gcc/mingw32/4.7.1/include-fixed
End of search list.
# 1 "<stdin>"
Argument tokens in Windows traditionally use the " character. I'm thinking the single quotes are being interpreted as part of the path names, resulting in the "no such file or directory" errors. That would explain why it works in PowerShell, though, as single quotes are valid there.
See if you have better luck with this:
g++ -o imageProcessing imageProcessing.cpp -lgdi32 -Dgmic_use_jpeg -I"C:\GnuWin32\include" -L"C:\GnuWin32\lib" -ljpeg

MinGW won't compile, Error 1

Making a simple hello world app in c++, but it won't compile. I have the folder C:\WiiGames\e3\ with the files main.cpp and Makefile. My makefile is:
build: main.cpp
C:/MinGW/bin/g++.exe main.cpp -o e3.exe
My error is:
C:\WiiGames\e3>make build
C:/MinGW/bin/g++.exe main.cpp -o e3.exe
make: *** [build] Error 1
C:\WiiGames\e3>
Any help would be greatly appreciated.
My code:
#include <iostream>
#include <stdio.h>
#include <string>
#include <cmath>
#include <cstdlib>
#include <time.h>
int main() {
printf("Hello World!");
}
g++ -v:
Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=c:/mingw/bin/../libexec/gcc/mingw32/4.6.2/lto-wrapper.exe
Target: mingw32
Configured with: ../gcc-4.6.2/configure --enable-languages=c,c++,ada,fortran,objc,obj-c++ --disable-sjlj-exceptions --with-dwarf2 --enable-shared --enable-libgomp --disable-win32-registry --enable-libstdcxx-debug --enable-version-specific-runtime-libs --build=mingw32 --prefix=/mingw
Thread model: win32
gcc version 4.6.2 (GCC)
Make sure it is a tab rather than spaces in the make file before the c:/mingw... Line. It looks like it is make giving the error, not g++.
What happens when you run g++.exe main.cpp -o e3.exe on the command line directly? If nothing happens, is g++ in your path? I'd start by making sure that g++ is setup and in your path.
Yes, it's an old question. These are some solutions i came across (YMMV a lot):
Check if your paths start with c:/ as opposed to /c/ or vice-versa.
Check if you're running in the right shell, i.e., one of:
c:\msys64\msys2_shell.cmd -mingw32
c:\msys64\mingw32.exe
c:\msys64\usr\bin\bash.exe
which may differ if used within an IDE.