How to link C library in Ruby extension - c

I'm building a relatively simple C extension to count pixels in a PNG file using libpng; I built the original version in C and it compiles (and works) fine in Cygwin with the command:
gcc -o shadow_counter shadow_counter.c -lpng
If I don't include the "-lpng" command it won't compile and kicks out a bunch of errors when trying to read the libpng functions ("undefined reference to `png_sig_cmp' ", etc.)
In order to package it for ruby, I put together the gemspec and files and folders and build it into a gem:
gem build shadow_png.gemspec
Then I head over to Powershell and install the gem:
gem install shadow_png-0.0.1.gem
If I leave out the libpng stuff, it installs fine and talks to Ruby the way it's supposed to. But once I start trying to reference the libpng functions and try to install it, it starts kicking out the SAME errors that I saw above (undefined reference to `png_sig_cmp' etc.). So my theory is that somehow the linking command -lpng isn't included.
How do I include these instructions as part of the process? Is it something I need to add to the gemspec? Or the command to build the gem? Or does it have to happen in the gem installation?
Thanks!

I think you're looking for the have_library method, to be placed in your extconf.rb file.
i.e.
abort 'Missing PNG library.' unless have_library('png')

Related

How can I compile a C console program using Cairo library (that compiles ok on Ubuntu) on Windows 11?

I made a console C program that reads a .obj 3d model and unflatten it into a multipage PDF. At first I used a little PDF library (https://github.com/AndreRenaud/PDFGen) that worked fine and I was able to compile my code on Windows 11, but I needed to have text rotated and it wasn't possible with PDFGen, so I changed for Cairo Library (https://github.com/freedesktop/cairo). With Cairo my code does exactly what I want, but I didn't find how to compile it on Windows.
I'm using Geany to edit/compile my C code, my build command is :
gcc -Wall -o "%e" "%f" -lcairo -lm
I tried to do the same on Geany on Windows and it didn't work.
I found a repository with standalone cairo DLL for Windows, but didn't manage to use it.
I'm looking for another PDF library that could be used both on Linux and Windows, but for the moment didn't find any.
my code is here (https://github.com/gilboonet/Deplieur-C/blob/main/deplieur.c)
It's my first post here, I'm a long time C programmer but not IT pro and I'm not a Windows user, I only want to compile my code on it because lots of people that will use my program are windows users. Thank you.
I've found a project called "cairo-windows" on Github that creates resources needed to build a C project using Cairo, and it works, even if I needed to use Visual Studio. Sadly, it seems to have problem with pdf creation that only creates a blank file. To make it work I changed the resources (dll and includes) it needs to build the project to those from my gtk windows build it comes with Cairo 1.16.0. If you want to do the same, you must replace the extern directory from cairo-windows (initially fetched by setup-win32.py): lib by cairo.lib, cairo.dll expat.dll fontconfig-1.dll freetype-6.dll and libpng16.dll from your gtk build (..gtk\x64\release\bin) and include by the content of ..\gtk\x64\include.

How to modify a project Makefile to integrate boehm gc

Please, is someone familiar with Boehm GC?
I want to use it in the word-count app of Phoenix (https://github.com/kozyraki/phoenix), but I fail to modify the Makefile to include the GC library.
On the documentation page of Boehm, they only provide a simple c example and a command to compile it from the GC directory tree. I can't find any tutorial on how to link it with an existing project.
Thanks
The following steps should help you:
ensure libgc is installed on your host, e.g. on Ubuntu type like this: sudo apt install libgc-dev
your source files (which call GC_* functions) should include <gc.h>.
add -lgc to LIBS variable in the Makefile

Why can my C program run in "git bash", but not in "cmd"?

I wrote a demo using libpq to connect to a PostgreSQL database.
I tried to connect the C file to PostgreSQL by including
#include <libpq-fe.h>
after I added the paths into system variables I:\Program Files\PostgreSQL\12\lib as well as to I:\Program Files\PostgreSQL\12\include and compiled with this command:
gcc -Wall -Wextra -m64 -I "I:\Program Files\PostgreSQL\12\include" -L "I:\Program Files\PostgreSQL\12\lib" testpsql.c -lpq -o testpsql
It first raised three errors, like
libssl-1_1-x64.dll is missing
libintl-8.dll was missing
libcrypto-1_1-x64.dll was missing
After I downloaded these three files and put them into I:\Program Files\PostgreSQL\12\lib, and compiled it again, it shows the error
The application was unable to start correctly (0xc0150002)
when I type testpsql. But if I type ./testpsql on git bash, it works. Anyone can please tell me why?
The code that I used was the first example from here.
Environment: PostgreSQL 12, Windows 10, MinGW64
“Download the DLL files” sounds dangerous. From where?
I would get rid of these files again. Since you probably don't reference these libraries from your code, it must be the dependencies of libpq.dll and are probably found in I:\Program Files\PostgreSQL\12\bin (if you used the EDB installer).
The problem is probably that you the PATH environment variable is different in git bash and in cmd.exe, and in the latter case not all required shared libraries can be found on the PATH. The solution is to change the PATH so that it includes all DLL files the executable requires, not to start copying around files.
It is probably enough to include I:\Program Files\PostgreSQL\12\bin in the PATH. To resolve missing dependencies, use a tool like dependency walker or this replacement.

Compiling go library without GCO to run on alpine, error in libczmq

When trying to run my binary on alpine, I got the error:
... binary not found
which typically happens when there's a problem with architecture, or as I found, glibc. I searched and discovered that alpine instead uses muslc, an alternative C library. I then found this Installed Go binary not found in path on Alpine Linux Docker that teaches how to compile without CGO, which is the thing that permits loading C libraries from go:
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o [name of binary]
When I run this, I get:
go build gopkg.in/zeromq/goczmq.v4: no buildable Go source files in /home/lucas/Go/src/gopkg.in/zeromq/goczmq.v4
I suspect that it's because libczmq is just a wrapper for the C written libzmq. In this case, how do I compile in a way that I can use libczmq? Why exactly CGO must be disabled in alpine?
What's exactly CGO? Shouldn't it use libc when available but muslc when not? I'd like to know more about what's happening in the background.
Note: I'm compiling outside alpine, in ubuntu, is that a problem?
I know this question is about three years old now but there is nothing on the Internet about this and I was facing the exact same problem and it took about two days before I finally found a proper solution.
In short, I had a Go project that uses goczmq that I wanted to compile to a complete binary to put it into a FROM scratch Docker container (although in this case, an alpine container would work just as well). On the Internet, people now tend to tell you to set CGO_ENABLED=0 and everything will work fine, which is true. This tells Go to not use CGO, which allows you to use C libraries in your Go code, but needs those C libraries to be available on the system when you run your code. As you have figured out, alpine does not have those C libraries (or, well, it has different ones in muslc instead of glibc).
However, in our case, this is not helpful. We want our Go code to be able to use existing C libraries because we use goczmq, which, as you have identified, is a Go wrapper for czmq which itself is a C wrapper for libzmq (which is written in C++, which makes our life even harder).
I solved this problem by using a static binary. Instead of linking to whatever C libraries are available on the target system (in this case muslc on alpine) dynamically, I compile my code AND all the libraries (muslc, czmq and libzmq) into one unified binary.
I'm using Docker multi-stage builds based on alpine here but in theory you could also do this directly on your computer.
# stage 1: build the binary
# we are using alpine Linux with the latest version of golang
FROM golang:1.13-alpine as golang
# first install some dependencies
# (we are using the static versions for each for them as we want these libraries included statically, not dynamically!)
# czmq requires libzmq which in turn requires libsodium
# on alpine Linux we also need to install some specific tools to build C and C++ programs
# libsodium also requires libuuid, which is included in util-linux-dev
RUN apk add --no-cache libzmq-static czmq-dev libsodium-static build-base util-linux-dev
# now we do the magic command mentioned here
# https://stackoverflow.com/questions/34729748/installed-go-binary-not-found-in-path-on-alpine-linux-docker?noredirect=1&lq=1
# this fools the C compiler into thinking we have glibc installed while we are actually using musl
# since we are compiling statically, it makes sense to use musl as it is smaller
# (and it uses the more permissive MIT license if you want to distribute your binary in some form, but check your other libraries before!)
RUN mkdir /lib64 && ln -s /lib/libc.musl-x86_64.so.1 /lib64/ld-linux-x86-64.so.2
# create your project directory for the Go project
WORKDIR /go/src/github.com/<username>/<projectname>/
# copy in all your Go files, assuming these are in the same directory as your Dockerfile
COPY . .
# here is the first hack: we need to tell CGO to use g++ instead of gcc or else it will struggle with libzmq, which is written in C++
# creating and empty C++ file actually works for this
RUN touch ./dummy.cc
# now run go install (go build could also work here but your binary would end up in a different directory)
# the -ldflags will be passed along the CGO toolchain
# -extldflags is especially important here, it has two important flags that we need:
# -static tells the compiler to use static linking, which does the actual magic of putting everything into one binary
# -luuid is needed to correctly find the uuid library that czmq uses
RUN go install -a -ldflags '-linkmode external -w -s -extldflags "-static -luuid" ' .
# stage 2: here is your actual image that will later run on your Docker host
# you can also use alpine here if you so choose
FROM scratch
# now we just copy over the completed binary from the old builder image
COPY --from=golang /go/bin/<projectname> bin
# and we start our program
ENTRYPOINT ["./bin"]
Now this almost works! The only thing left is to add this statement to the beginning of your main.go file or else CGO is confused about what you are doing:
import "C"
This is important even if you don't directly use CGO in your program.

Statically Linking glib

I'm trying to statically link glib into my C program. I'm not sure what's the best way to do this. I downloaded the code and put it in a subdirectory called glib-2.36.4. I added "-Iglib-2.36.4" when using gcc. The glib.h is in the glib-2.36.4/glib directory and in that file there are references to other header files under the glib directory (such as #include ).
I'm not sure why that is since both glib.h and these other header files are at the same level (in glib subdirectory). I got a compile error due to galloca.h not being found (even though it's there). So I copied glib.h up one level and those errors went away. I then got an error about a missing glibconfig.h. I copied that from my usr directory and that error went away. I compiled my project and now I'm getting an error about undefined reference to g_ptr_array_new. I guess this must be because I haven't actually compiled glib. I had tried to build glib, but when I typed "./configure", but I got this message:
checking if arpa/nameser_compat.h is needed... configure: error: could not compile test program either way
I did install glib using yum, but I really want this code to run even if glib is not installed on a machine.
You need to install both glib and glib-dev via yum, compile using ./configure, (take a look in the ./configure script to see if there are any flags you need to supply or defines you need to produce the static build), without moving any files about, and then you need to compile your code using -i path/to/glib/includes and link with -L path/to/built/static/library

Resources