Linking glfw and D - linker

I'm trying to use glfw 2.7.8 with the Digital Mars D compiler version 2.0.
I followed the instructions from the example makefile on copying the .lib files to dm/lib folder, but I have not had success.
An example compile looks like this.
dmd main.d
The source of the file is:
import std.string;
import glfw;
int main()
{
glfwInit();
return 0;
}
The output I get is
main.d(2): Error: module glfw is in file 'glfw.d' which cannot be read
import path[0] = /usr/share/dmd/src/phobos
import path[1] = /usr/share/dmd/src/druntime/import
I have tried on both Windows 7 and Mac OSX 10.8.2, but I have not had success. Should I compile glfw.d as a lib and then drop it into my main directory?
I have also had _symbol not found messsages when I try to drop the .lib into the main directory and use the -L compiler flags linking to glfw.lib.
Any examples or help would be much appreciated.

you need to add -Ipath/to/glfw-x.x.x/support/d/imports to the compiler directive
you can also add the lib folder (with the def files) with the -L switch so the linker can map the symbols properly to the ones exposed in the dll

You need to pass glfw.d to the compiler:
dmd main.d glfw.d
assuming it is in the same directory as main.d.

Related

"Compiling" go project as C shared object library on AIX 7.2 results in Executable that doesn't run

EDIT: For any poor soul that finds this, in search of a solution for the shared library from go conundrum: I was unable to find a solution that uses go and I would suggest, that until google go provides native c-shared support for AIX you should find an alternative for your project.
I did not go forward with gccgo because that felt like an entirely different can of worms that I was unwilling to delve further into. FWIW I myself am going forward switching to pure C implementation, because there I at least have a (somewhat) firm(er) understanding of it all.
Should anyone find a solution I'd love to hear from you and see how you got around this limitation.
Environment:
AIX 7.2
go1.16.12 aix/ppc64
gcc-8
I want to create a C shared object library (in usual unix vernacular a .so file) out of a golang project on AIX 7.2 so that it can be used by a C application.
I can compile it down to a final a.out binary in my example, but it can then not be executed because the shared object is apparently compiled the wrong way.
So far I have achieved the following:
Suppose my example go "library" sharedLibTest.go:
package main
import (
m "fmt"
)
import "C"
func main() {
fmt.Printf("%s\n", "Golang: main was called")
MyPackage_Init()
MyPackage_Create()
}
//export MyPackage_Init
func MyPackage_Init() {
fmt.Printf("%s\n", "Golang: MyPackage_Init was called")
}
//export MyPackage_Create
func MyPackage_Create() {
fmt.Printf("%s\n", "Golang: MyPackage_Create was called")
}
And some C application that calls these functions in main.c:
#include <stdio.h>
#include "sharedLibTest.h"
int main() {
printf("%s\n", "C: main() called");
MyPackage_Init();
MyPackage_Create();
}
m
Now, because AIX feels the need to do things differently the current golang toolchain does not support directly creating a c-shared object with -buildmode=c-shared. Instead I am trying to do the roundabout way by first creating a static lib with -buildmode=c-archive, compiling that into a shared object using gcc-8 and use that in my "target C application".
I can compile sharedLibTest.go this with
go build -v -buildmode=c-archive -mod vendor -o /home/myuser/workspace/go_proj/sharedLibTest/sharedLibTest.a /home/myuser/workspace/go_proj/sharedLibTest/sharedLibTest.go
Because the symbols MyPackage_Init and MyPackage_Create are not exported by default in AIX, I need to manually create an extra symbol file with
$ cat > file.exp << EOF
> MyPackage_Init
> MyPackage_Create
> EOF
Source
(If there are any ideas how i can omit this file.exp step I'd really appreciate it)
Now with that I can compile a shared object out of that by running
gcc -g -O2 -mcpu=power7 -maix64 -shared -lpthread -Wl,-bE:file.exp -o libsharedLibTest.so -Wl,-bnoobjreorder ./sharedLibTest.a
Now because AIX does not look for .so files but only .a files even if they are shared libraries, I rename the resulting libsharedLibTest.so into libsharedLibTest.a with
mv libsharedLibTest.so libsharedLibTest.a
Lastly I want to compile my C applications with
gcc -L/home/myuser/workspace/go_proj/sharedLibTest -g -O2 -mcpu=power7 -maix64 -Wl,-bnoobjreorder -lsharedLibTest -lpthreads main.c
This succeeds and I get my a.out file as a result.
However, when I try to run this with the following, I only get the error below
LD_LIBRARY_PATH=/home/myuser/workspace/go_proj/sharedLibTest ./a.out
$ ./a.out
exec(): 0509-036 Cannot load program ./a.out because of the following errors:
0509-150 Dependent module /home/myuser/workspace/go_proj/sharedLibTest/libsharedLibTest.a(libsharedLibTest.so) could not be loaded.
0509-187 The local-exec model was used for thread-local
storage, but the module is not the main program.
0509-193 Examine the .loader section header with the
'dump -Hv' command.
Some hours of googling so far have revealed that I might be missing the compile option -fPIC to create "emit position-independent code" however adding that flag to any of the above steps in various combinations has all resulted in the same error.
Clearly I need to add some compile option to tell the shared object not to be thread-local, however I am unclear how. Any ideas?
Few points... mv will not make an archieve, ar will. You need to use ar command to create .a file.
Second, use LIBPATH environment variable in place of LD_LIBRARY_PATH. Use of -fPIC option is irrelevant on AIX.

MinGW/GCC GLFW linker issue - undefined reference to "glfwInit"

TL;DR - I have tried all solutions I could find, nothing has worked so far.
Hello, I have searched far and wide but I cannot find an answer to my problem. When I try to compile my C program with GCC, I get an undefined reference to glfwInit(). First, I tried putting the glfw .dll in the same location as the program, which did seemingly nothing. After this I tried removing the glfw libraries from MinGW's "lib" directory and replacing them with the .dll, and adding #define GLFW_DLL to the top of my .c file (same error). I also tried changing the linking order around, adding -lopengl32 and -lgdi32, renaming one of the static libraries just in case the compiler was confused, etc. Nothing seems to be working here, but I have previously installed and developed with SDL2 in the same fashion.
main.c:
#include<stdio.h>
#include<GLFW/glfw3.h>
int main(int argc, char **argv) {
if(!glfwInit()) {
printf("Failed!");
return -1;
}
printf("Success!");
getch();
return 0;
}
Instructions to the compiler:
gcc -std=c99 -o project.exe main.c -lglfw3 -lglfw3dll
Alright, I have finally solved the problem. I followed the instructions in this video: https://www.youtube.com/watch?v=bIK95aWk-Bo. The gist of the video is that you need to download CMake as well as the GLFW version found here: https://www.glfw.org/
Then, you need to hit "Configure" after setting the source and build paths. After this, hit "Generate." Then, you need to open a command prompt and locate the newly created MakeFile. I am using Windows, which means I needed to use the command mingw32-make. The library files then built successfully!
After doing this, I put the created .dll and .a files in the MinGW "lib" folder. Then, I copied the .dll and placed it in the same directory as my executable.

Fail to find a function in yaml.h library (C)

I try to read a yml file in C (Code::Blocks IDE) but I receive an undefined reference error for yaml_parser_initialize:
#include <stdio.h>
#include <stdlib.h>
#include <yaml.h>
int main(){
FILE *fh = fopen("configuration.yaml", "r");
yaml_parser_t parser;
/* Initialize parser */
if(!yaml_parser_initialize(&parser))
fputs("Failed to initialize parser!\n", stderr);
fclose(fh);
return 0;}
The function exists in yaml.h. I linked the yaml library as follows:
Project->Build Options->Linker Settings: added src\.libs\libyaml.a
Project->Build Options->Search Directories->Compiler: added the include library: yaml-0.2.5\include.
Project->Build Options->Search Directories->Linker: added the include library: yaml-0.2.5\include.
OS: Win10
Thanks in advance.
In short, I will try to answer that and update my answer per request.
If you building on Linux OS, no matter if your host OS is Windows(you may run Linux as a virtual machine), you usually link with .a or .so library files.
If you build envinronment is Windows, no matter the host OS, then you usually link with .lib or .dll libraries.
That being said, the above mentioned OS'es have a different convention about how to supply a path to file.
On Linux the path go like this: /path/to/libs/libyaml.a.
On Windows the path go like this C:\Program Files\libs\yaml.lib.
Any app that runs on the OS follow the OS path convention. In your case Code::Blocks request you to supply a path in the convention the guest OS is.
The below text, is two methods of building your code with yaml library ob Ubuntu.
Update
I do not use Code::Blocks as of now. I've installed the IDE to check what your options are.
You talk about Ubuntu, C and yaml. That will be:
1) New Project->Console Application->C.
2) <Whichever project names you wish>
3) <Whatever compiler configuration you like>
That was to create a bunch of files that CB calls project. Now I dont know what sort of yaml library you use. But you talk about Ubuntu and C so...
1) apt search libyaml-><guess what yaml are>->apt install libyaml-dev
2) pkg-config --list-all | grep yaml gets me the output of yaml-0.1. That is the name I want to supply as argument to pkg-config.
BTW you seem to get a different version of yaml library. But still, all we need is to know proper strings to supply as compiler and linker arguments.
3) pkg-config --libs gets me -lyaml
4) pkg-config --cflags gets me empty line. So the include path is well-known for the build envinronment
This way, we know the linker arguments(-lyaml) and the compiler arguments(<empty string>). Now I try to insert them somewhere where CB could find them.
1) Menu options: Project->Build options...
2) Compiler settings-> no change
3) Linker settings->link libraries->yaml
The libraries in CB should go without -l prefix, so it should be as above. Hit build and all went OK.
Update for git version
It seems that your yaml version is newer than my distro version. If you need recent version, lets go and install that from git.
1) apt remove libyaml-dev. So that there will be no clashes with the library versions.
I did choose the Canonical repository for libyaml as my distro is Ubuntu. You need to mkdir for the sources and cd to that directory.
2) git clone https://github.com/yaml/libyaml
3) cd libyaml
4) Follow the instructions to build and install.
5) pkg-config --list-all | grep yaml gets me yaml-0.1
6) pkg-config --cflags yaml-0.1 produces -I/usr/local/include
7) pkg-config --libs yaml-0.1 gets this -L/usr/local/lib -lyaml
Ok we got the compiler & linker flags for the library. The link library option stays the same. You need to add -L/usr/local/lib to Other linker options. I did not find where I could add the compiler flags, so I'had added new flag. In CB that will be Compiler flags-><right mouse click>->New flag. Name the flag somehow and insert the -I/usr/local/include string to the Compiler flags input row. Hit OK button. Hit the checkbox in front of your newly created flag. Build & Run.

Import readline.h library to QtCreator on Windows

I need to import readline.h library to Windows. I have already tried to import folder with libraries here:
C:\Qt\Tools\mingw492_32\i686-w64-mingw32\include
It is a library with history.h, chardefs.h, keymaps.h, readline.h, etc..
But when i try to compile program like this:
if ((line= readline("my_prompt$ ")) == NULL)
exit(0);
add_history(line);
I recieve this message:
error: undefined reference to `add_history'
error: undefined reference to `impl__readline'
I really need it to run that library on my machine. Thanks you very much for helping!
You need to add the library path to your .pro file (not your Makefile - this will be rewritten everytime you change anything in your project configuration):
LIBS += -lreadline

Link against a Windows .dll+.lib file combination with GCC under Cygwin?

I know how to link against libraries in Unix-ish contexts: If I'm working with .a or .so files, I specify the root search directory with -L/my/path/to/lib/ and for libMylib I add -lMyLib.
But what if I have
a .dll (e.g. in the Windows\System32 directory)?
a .dll (in Windows\System32) and a .lib (someplace else)?
These DLLs are by some other party; I don't have access to their sources - but do have access to the corresponding include files, against which I manage to compile.
If you can link against a .lib in Cygwin or MinGW, then you can (indirectly) link against a DLL.
In the MSVC world, it is not unusual to create an import library along with a DLL. It is a static library (.lib) that loads the DLL and wraps the interface of the DLL. You just call the wrapper functions in the (static) import library and let the import library do all the DLL-related things.
For the Windows API, there are import libraries in the WindowsSDK.
For your own MSVC DLLs, MSVC can automatically generate the import libraries when you build the DLL.
For a third party DLL, you can build a static wrapper library based on the corresponding header files.
Linking against the .lib file in Cygwin or MinGW is possible. Example:
g++ -o myprg myprg.o -lShlwapi
This links against Shlwapi.lib. (The library must be in the local directory or in the library path of the linker.)
Linking against import libraries of DLLs works the same way.
Note 1: Keep in mind the different ABIs and name mangeling. However, calling plain C functions in DLL or LIB files will work in most cases.
Note 2: Keep in mind that g++ requires the libraries to be specified in the correct order.
#einpoklum Converting my comment to an answer: #n.18e9 is correct in that you must use the full path name for the lib file without any -L or -l options.
g++ -o foo.exe foo.o c:\something\somethingelse\some.lib. You can also link directly to the Windows DLL file g++ -o foo.exe foo.o c:\something\somethingelse\some.dll.
Important - make sure you are linking to a lib file (and associated dll) generated for a 64-bit platform (on MSVC target X64, not Win32).
OK you wanted an example, well let's go.
Here are two examples using gcc/g++ to link to a Windows native DLL which exports plain C functions (using here x86_64-w64-mingw32/8.3.0 on Windows 10).
I'm using my own free xmlsq library as an example https://www.cryptosys.net/xmlsq.
You can download the core native DLL and all the source code quoted below. Make sure you use the 64-bit DLL.
The native Windows DLL diXmlsq.dll is written entirely in plain C code and exports simple C functions (extern "C").
In particular, for this example, it exports a XMLSQ_Gen_Version function that returns an integer value.
The DLL was compiled using MSVC 12.0 targetting the X64 platform. The associated library file generated by MSVC is diXmlsq.lib.
I should add that this DLL works exactly the same as a Windows "Win32 API" DLL, so the instructions here should work for the standard Windows libraries in Windows\System32 (again make sure you link against the 64-bit version).
Example 1. A plain C interface.
Both these commands compile without warning on my system:
> gcc -o test-ver test-ver.c "C:\fullpath\to\x64\diXmlsq.lib"
> gcc -o test-ver test-ver.c "C:\fullpath\to\x64\diXmlsq.dll"
diXmlsq.dll is compiled using the following definition file.
(You could alternatively use __declspec(dllexport))
Ref: https://learn.microsoft.com/en-us/cpp/build/exporting-from-a-dll?view=msvc-160
diXmlsq.def
LIBRARY "diXmlsq"
EXPORTS
XMLSQ_Gen_Version
diXmlsq.h - the C interface to diXmlsq.dll
#ifdef __cplusplus
extern "C" {
#endif
long __stdcall XMLSQ_Gen_Version(void);
#ifdef __cplusplus
}
#endif
To call the core function in a plain C program:
test-ver.c
#include <stdio.h>
#include "diXmlsq.h"
int main(void)
{
long n;
n = XMLSQ_Gen_Version();
printf("Version = %ld\n", n);
return 0;
}
Example 2. A C++ interface.
Both these commands compile without warning using g++ .
> g++ -o test-simple test-simple.cpp xmlsq.cpp "C:\fullpath\to\x64\diXmlsq.lib"
> g++ -o test-simple test-simple.cpp xmlsq.cpp "C:\fullpath\to\x64\diXmlsq.dll"
The idea of the C++ interface is to be an interface to the plain C library using the more convenient STL types like std::string and std::vector.
To keep things simple we'll just demonstrate the Gen::Version method.
Extracts of the C++ code follow:
test-simple.cpp - a test C++ program.
#include <iostream>
#include "xmlsq.hpp"
int main()
{
std::cout << "xmlsq::Gen::Version=" << xmlsq::Gen::Version() << std::endl;
}
xmlsq.hpp - the C++ interface
namespace xmlsq
{
class Gen {
private:
Gen() {} // Static methods only, so hide constructor.
public:
/** Get version number of core diXmlsq DLL. */
static int Version();
};
}
xmlsq.cpp - the C++ implementation.
#include "diXmlsq.h"
#include "xmlsq.hpp"
namespace xmlsq
{
int Gen::Version() {
int n = XMLSQ_Gen_Version();
return n;
}
}
Example 3. Attempting to link to the 32-bit library by mistake.
> gcc -o test-ver test-ver.c "C:\fullpath\to\Win32\diXmlsq.lib"
C:/Strawberry/c/bin/../lib/gcc/x86_64-w64-mingw32/8.3.0/../../../../x86_64-w64-mingw32/bin/ld.exe:
C:\Users\user\AppData\Local\Temp\cce27Dhl.o:test-ver.c:(.text+0xe):
undefined reference to `XMLSQ_Gen_Version'
collect2.exe: error: ld returned 1 exit status

Resources