Using `pkg-config` as command line argument under cygwin/msys bash - windows

I'm trying to use cygwin as a build environment under Windows. I have some dependencies on 3rd party packages, for example, GTK+.
Normally when I build under Linux, in my Makefile I can add a call to pkg-config as an argument to gcc, so it comes out like so:
gcc example.c `pkg-config --libs --cflags gtk+-2.0`
This works fine under Linux, but in cygwin I get:
:Invalid argument
make: *** [example] Error 1
Right now, I am just manually running pkg-config and pasting the output into the Makefile, which is truly terrible. Is there a good way to workaround or fix for this issue?
Make isn't the culprit. I can copy and paste the command line that make uses to call gcc, and that by itself will run gcc, which halts with ": Invalid argument".
I wrote a small test program to print out command line arguments:
for (i = 0; i < argc; i++)
printf("'%s'\n", argv[i]);
Notice the single quotes.
$ pkg-config --libs gtk+-2.0
-Lc:/mingw/lib -lgtk-win32-2.0 -lgdk-win32-2.0 -latk-1.0 -lgdk_pixbuf-2.0 -lpang
owin32-1.0 -lgdi32 -lpangocairo-1.0 -lpango-1.0 -lcairo -lgobject-2.0 -lgmodule-
2.0 -lglib-2.0 -lintl
Running through the test program:
$ ./t `pkg-config --libs gtk+-2.0`
'C:\cygwin\home\smo\pvm\src\t.exe'
'-Lc:/mingw/lib'
'-lgtk-win32-2.0'
'-lgdk-win32-2.0'
'-latk-1.0'
'-lgdk_pixbuf-2.0'
'-lpangowin32-1.0'
'-lgdi32'
'-lpangocairo-1.0'
'-lpango-1.0'
'-lcairo'
'-lgobject-2.0'
'-lgmodule-2.0'
'-lglib-2.0'
'-lintl'
'
Notice the one single quote on the last line. It looks like argc is one greater than it should be, and argv[argc - 1] is null. Running the same test on Linux does not have this result.
That said, is there, say, some way I could have the Makefile store the result of pkg-config into a variable, and then use that variable, rather than using the back-tick operator?

That said, is there, say, some way I could have the Makefile store the result of pkg-config into a variable, and then use that variable, rather than using the back-tick operator?
GTK_LIBS = $(shell pkg-config --libs gtk+-2.0)

Are you sure that you're using the make provided by Cygwin? Use
which make
make --version
to check - this should return "/usr/bin/make" and "GNU Make 3.8 [...]" or something similar.

Hmmm... have you tried
make -d
That will give you some (lots) of debugging output.

My guess would be that cygwin's gcc can't handle -Lc:/mingw/lib. Try translating that to a cygwin path.
GTK_LIBS = $(patsubst -Lc:/%,-L/cygdrive/c/%,$(shell pkg-config --libs gtk+-2.0))

The single quote at the end of the "t" output may be an artifact of CRLF translation. Is your pkg-config a cygwin app? The $(shell) solution I posted earlier may help with this, as GNU make seems to be fairly tolerant of different line ending styles.

I had a similar issue and I found a fix here: http://www.demexp.org/dokuwiki/en:demexp_build_on_windows
Take care to put /usr/bin before /cygwin/c/GTK/bin in your PATH so that you use /usr/bin/pkg-config. This is required because GTK's pkg-config post-processes paths, often transforming them in their Windows absolute paths equivalents. As a consequence, tools under cygwin may not understand those paths.

Related

Cannot pass flags to Makefile to compile my code

I have a project that basically compiles from the command line in the following form:
g++ -o stack_raster stack_raster.cpp -lgdal -lboost_filesystem -lboost_system
I made a Makefile, and this is the content:
CXX =g++
LDDFLAGS = -lgdal -lboost_system -lboost_filesystem
all: clean stack_raster
clean:
rm -f stack_raster
However I got a collect2: error: ld returned 1 exit status.
A second variation of my Makefile I tried was:
CXX = g++
CPPFLAGS = -lgdal -lboost_system -lboost_filesystem
all: clean stack_raster
clean:
rem -f stack_raster
but I still receive the following message (even though the compile flags appear as they should for my program to compile successfully).
collect2: error: ld returned 1 exit status
<builtin>: recipe for target `stack_raster` failed
make: *** [stack_raster] Error 1
Does anyone could help me with a reference or hint about my problem, and how could I tackle it?
Does anyone could help me with a reference or hint about my problem, and how could I tackle it?
To begin with, you should have a look at the actual link command that make executed. It should have been echoed to make's output just before the error message from collect2. Understanding what's wrong with the command is the first step in determining how to fix your makefile.
In the first case, the command is probably something like
g++ stack_raster.cpp -o stack_raster
In the second, it is probably something like
g++ -lgdal -lboost_system -lboost_filesystem stack_raster.cpp -o stack_raster
The latter is probably also very similar to what you would get with the first makefile if you corrected the spelling of LDDFLAGS to LDFLAGS.
You will note that the library flags come in a different place in that command than they do in your manual command, and I assume you know that the order of objects and library flags on the linker command line is significant to Unix-style linkers such as GNU's (which is the one that the g++ driver will use).
You can certainly fix this by writing an explicit rule, as you describe in your own answer, but your makes' built-in rules may be up to the task, too. If you are using GNU make then they certainly are. For this purpose it is useful to know what the built-in rules actually are, and essential to know what the variables on which these rules depend mean.
Specifically,
LDFLAGS provides options to pass when invoking the linker, and conventionally, they appear on the command line before the objects being linked. As a result, this variable typically is not appropriate for specifying libraries (but it is fine for other link-specific options, such as -L to add directories to the library search path).
CPPFLAGS provides options for modulating the behavior of the C preprocessor (including when compiling C++). These do not typically appear at all in link(-only) commands executed by make, but they will appear (early) in commands for compiling object files from C or C++ sources, and in rules for building executables directly from C or C++ sources.
Neither of those is what you want, but if you are using GNU make, then its documentation for the former explicitly tells you what (with that make implementation) you should do instead:
Extra flags to give to compilers when they are supposed to invoke the
linker, ‘ld’, such as -L. Libraries (-lfoo) should be added to the
LDLIBS variable instead.
(emphasis added)
In GNU make, and perhaps some others, the LDLIBS variable serves exactly the purpose you need: to specify the libraries to link. These will appear at the end of the link command line from built-in rules, as you can confirm from GNU make's catalog of implicit rules, or from the list obtainable by running make -p in a directory containing no makefile.
So, with GNU make you can get the build you seem to want from the built-in rules, with this:
CXX = g++
LDLIBS = -lgdal -lboost_system -lboost_filesystem
all: clean stack_raster
clean:
rm -f stack_raster
In closing, I note that cleaning before building by default, as your examples do and mine imitates, largely defeats the purpose of using make instead of a simple script. Part of the point of make is to do the minimum work necessary, and if your target executable is present and not out of date with respect to its sources then there is no reason to force it to be rebuilt.
Check out the answer:
Set up my makefile to compile C with just "make"
YOu have to specify in the Makefile the file you want to create in this case stack_raster.exe and the objective file in this case stack_raster.cpp and specify the command line arguments you normally pass for compiling. So the Makefile would be something like:
CXX=g++
stack_raster.exe: stack_raster.cpp
g++ -o stack_raster.exe stack_raster.cpp -lgdal -lboost_filesystem -lboost_system
all: clean stack_raster.exe
clean:
rm -f stack_raster.exe

Ada Compilation Print full path

Simple question. I am compiling an ada program with gnat. The gcc command ends up looking like gcc -c -Ia -Ibunch -Iof -Iincludes -I- -o /some/object/file.o /some/source/file.adb however the error format consists of just file.adb:line:offset: problem.
Is there any way to get GNAT make or gcc to print the full path to the file in its errors, as specified on the command line? IE: to get /some/source/file.adb:line:offset: problem.
I know that with the -gnatv one could argue that it prints the full path, but I want something significantly less verbose than that.
you need -gnatef option:
-gnatef
Display full source path name in brief error messages.
gcc -gnatef -c %CD%\file.adb
C:\DATA\jff\data\python\stackoverflow\file.adb:1:01: "procedure" expected
https://gcc.gnu.org/onlinedocs/gcc-4.3.6/gnat_ugn_unw/Switches-for-gcc.html

How to customize the meaning of the "-l" flag for GCC?

I have problems with GCC and I would like to use the -l flags in a customized way.
I would like to specify the search path for the correspondant libfoo specified by -lfoo , I also would like to override any internal search path in GCC, i don't want GCC to use any random lib that can solve the symbols, I only want GCC to compile with a really specific lib when -l is specified.
I know that there are utils such as pkg-config but my problem is more gcc-centric because i'm focusing on having more control on the compilation steps.
There is an undocumented syntax for specifying an absolute lib path to gcc:
$ gcc -o test test.c -l:/usr/lib/libfoo.so #(note the colon)
See here: https://code.ros.org/lurker/message/20130119.001059.fad11362.de.html
A more standard way to do this would simply be:
$ gcc -o test test.c /usr/lib/libfoo.so
Really, the only reason to use the -l: syntax is if you have a conflicting library of the same name in your search path and you can't change the search path.

How to compile OpenSSL with relative rpath

I have been trying to compile openssl 1.0.0g with the following rpath:
$ORIGIN/../lib64
Everytime I readelf -d apps/openssl, I am getting results like the following depending on what escaping variation I tried:
\RIGIN/../lib64
RIGIN/../lib64
ORIGIN/../lib64
I want to setup my rpath without using external tools like chrpath. Is it at all possible? I will basically accept anything that does not involve using external tools like chrpath (though I would already be done with that).
Ideally, I would like to do it by passing options on the command line (any form of -Wl,-rpath,$ORIGIN/../lib64).
I don't mind editing the generated Makefile, which is what I have been trying last. If only I could get it to print a stupid dollar sign!!! I tried modifying LIBRPATH under the BUILDENV= block with no luck. My best results so far:
LIBRPATH=$$'ORIGIN/../lib64 # result: /../lib64
LIBRPATH=$$$$'ORIGIN/../lib64 # result: 12345<pid>/../lib64
I have read various rpath related questions and tried various escaping and quoting tricks but nothing worked so far!
In your makefile try:
-Wl,-rpath,${ORIGIN}/../lib64
I am assuming that the ORIGIN is a shell variable.
EDIT
I have just found an answer to your question (better late then never):
You need to prevent make from interpolating variables, to do that you need to use $$ (double dolar sign):
-Wl,-rpath,'$$ORIGIN/../lib64'
I know that it works because I have tested it with my own application, enjoy :)
I went the chrpath way.
http://enchildfone.wordpress.com/2010/03/23/a-description-of-rpath-origin-ld_library_path-and-portable-linux-binaries/
It is quite complicated to counter shell expansion of `$$ORIGIN`` in openssl. Sooner or later, it gets expanded because of the dollar sign. If you really want to go this way, you can do it. I have found the following to work with openssl 1.0.1g on Linux. In Makefile.shared, look for this line:
DO_GNU_APP=LDFLAGS="$(CFLAGS) -Wl,-rpath,$(LIBRPATH)"
Replace it with the following. This quoting-fu neutralize the expansion of $. The double $$ is the way to get a single dollar sign in makefiles.
DO_GNU_APP=LDFLAGS="$(CFLAGS) -Wl,-rpath,'"'$$'"ORIGIN/../lib64'"
After compiling:
readelf -d apps/openssl | grep RPATH
0x000000000000000f (RPATH) Library rpath: ['$ORIGIN/../lib64']
OK I spent several hours fighting with this same issue and trying all manner of crazy escaping, at one point I was up to eight $ signs, at which point I decided that there must be another way.
In fact, it appears that there is, at least with GNU ld.
Instead of -Wl,-rpath,\\$$$\$\$\$$$\$\\\\$ or some other elder god invoking monstrosity, just do this:
echo '-rpath=$ORIGIN/../lib64' > rpathorigin
./config -Wl,#$(pwd)/rpathorigin ...
I don't see that ld.gold documents the # flag, and I have no idea about, say, lld. But if you are using GCC and it is invoking BFD ld, the above may just work for you.
Of course, the actual path used with origin should be customized as needed, and I have no opinion on ./config vs ./Configure. But using the response file trick seems to entirely sidestep the shell/make escaping nightmare.
I don't mind editing the generated Makefile, which is what I have been trying last...
I'm not sure you can set it with a shell variable and relative path. I don't think ldd expands the $ORIGIN in $ORIGIN/../lib64. In this case, I think you need to use ldconfig to add $ORIGIN/../lib64 to the library search paths. See finding ldd search path on Server Fault for more details.
Since I'm not sure, I'll provide the instructions anyway. You don't need to change the Makefiles. As a matter of fact, I did not have any luck doing so in the past because things get overwritten, and other things like CFLAGS and LDFLAGS get ignored.
Also see Build OpenSSL with RPATH? Your question and the cited question are different question that converge on similar answers (no duplicates between them). But it provides the OpenSSL dev's position on RPATHs. It was a private email, so I shared the relevant details rather than the whole message.
If you manage to embed $ORIGIN/../lib64 in the ELF section and it works, then please report back. Below, I am using /usr/local/ssl/lib for my RPATH. You should substitute $ORIGIN/../lib64 for /usr/local/ssl/lib.
OpenSSL supports RPATH's out of the box for BSD targets (but not others). From Configure:
# Unlike other OSes (like Solaris, Linux, Tru64, IRIX) BSD run-time
# linkers (tested OpenBSD, NetBSD and FreeBSD) "demand" RPATH set on
# .so objects. Apparently application RPATH is not global and does
# not apply to .so linked with other .so. Problem manifests itself
# when libssl.so fails to load libcrypto.so. One can argue that we
# should engrave this into Makefile.shared rules or into BSD-* config
# lines above. Meanwhile let's try to be cautious and pass -rpath to
# linker only when --prefix is not /usr.
if ($target =~ /^BSD\-/)
{
$shared_ldflag.=" -Wl,-rpath,\$(LIBRPATH)" if ($prefix !~ m|^/usr[/]*$|);
}
The easiest way to do it for OpenSSL 1.0.2 appears to be add it to linker flags during configuration
./config -Wl,-rpath=/usr/local/ssl/lib
You can also edit Configure line and hard code the rpath. For example, I am working on Debian x86_64. So I opened the file Configure in an editor, copied linux-x86_64, named it linux-x86_64-rpath, and made the following change to add the -rpath option:
"linux-x86_64-rpath", "gcc:-m64 -DL_ENDIAN -O3 -Wall -Wl,-rpath=/usr/local/ssl/lib::
-D_REENTRANT::-Wl,-rpath=/usr/local/ssl/lib -ldl:SIXTY_FOUR_BIT_LONG RC4_CHUNK DES_INT DES_UNROLL:
${x86_64_asm}:elf:dlfcn:linux-shared:-fPIC:-m64:.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR):::64",
Above, fields 2 and 6 were changed. They correspond to $cflag and $ldflag in OpenSSL's builds system.
Then, Configure with the new configuration:
$ ./Configure linux-x86_64-rpath shared no-ssl2 no-ssl3 no-comp \
--openssldir=/usr/local/ssl enable-ec_nistp_64_gcc_128
Finally, after make, verify the settings stuck:
$ readelf -d ./libssl.so | grep -i rpath
0x000000000000000f (RPATH) Library rpath: [/usr/local/ssl/lib]
$ readelf -d ./libcrypto.so | grep -i rpath
0x000000000000000f (RPATH) Library rpath: [/usr/local/ssl/lib]
$ readelf -d ./apps/openssl | grep -i rpath
0x000000000000000f (RPATH) Library rpath: [/usr/local/ssl/lib]
Once you perform make install, then ldd will produce expected results:
$ ldd /usr/local/ssl/lib/libssl.so
linux-vdso.so.1 => (0x00007ffceff6c000)
libcrypto.so.1.0.0 => /usr/local/ssl/lib/libcrypto.so.1.0.0 (0x00007ff5eff96000)
...
$ ldd /usr/local/ssl/bin/openssl
linux-vdso.so.1 => (0x00007ffc30d3a000)
libssl.so.1.0.0 => /usr/local/ssl/lib/libssl.so.1.0.0 (0x00007f9e8372e000)
libcrypto.so.1.0.0 => /usr/local/ssl/lib/libcrypto.so.1.0.0 (0x00007f9e832c0000)
...
Don't ask me why but this worked for me in OpenSSL 1.1.1i in getting around the $ sign issue:
\$\$\$$ORIGIN
Example:
./Configure linux-x86_64 '-Wl,-rpath,\$\$\$$ORIGIN'
Alternatively, if this command line hack isn't congruent with you, you can always use chrpath after building as others have suggested:
./Configure linux-x86_64 '-Wl,-rpath,XORIGIN'
make depend
make all
chrpath -r "\$ORIGIN" libssl.so

How to set library search path for 64 bit libraries for g++ in Ubuntu?

Trying to compile something for 64 bit unix using Ubuntu. As a disclaimer I only started using linux and gcc a few days ago so still learning my way around. Anyway, getting the following error:
/home/myuser/myproject/myfile.cpp:437: undefined reference to `clock_gettime'
A quick google reveals I need the -lrt option to link with librt.a. So I check my command line ( formatted for readability, different file names and I've remove lists of file names ):
/usr/bin/g++
-Wl,
--gc-sections
-fno-exceptions
-m64
-B/usr/bin
-o
"/home/myuser/myproject"
-Wl,
-Map, "/home/myuser/myproject/myproject.map"
-g
"/home/myuser/myproject/myproject.cpp.obj"
..and some more .objs..
-Xlinker
--start-group
"-lpthread"
"-lrt"
"/home/myuser/myproject/lib/mylib.a"
..and some more .as..
-Xlinker
--end-group
Hmm. Looks like -lrt is already there, maybe I don't have librt.a? Nope searching all files reveals I have /usr/lib/x86_64-linux-gnu/librt.a. I guess g++ is looking in the wrong place. So in the above command line I replace -lrt with /usr/lib/x86_64-linux-gnu/librt.a and bingo! it compiles and links fine. Unfortunately, this is an automated tool and I need this to work on many computers and can't make assumptions about the location of librt.a so I really need it to work with -lrt. So how do I set the local libary search path? First attempt is changing LD_LIBRARY_PATH environment variable but apparently ( from what I can tell from more googling ) this is ignored on ubuntu and instead I should be messing with .conf files in /etc/ld.so.conf.d/, however I already it looks like I already have x86_64-linux-gnu.conf in there with the following lines:
# Multiarch support
/lib/x86_64-linux-gnu
/usr/lib/x86_64-linux-gnu
From my reading up this point it looks that should be all I need. Kind of stuck as to where to go from here...
Answering my own question just in case someone else has this problem. Turns out the correct librt.a was being linked but the linker is very sensitive to the link order. Putting -lrt and -lpthread at the end of the group fixes the problem.

Resources