I have an SDL2 program that I've been developing on Ubuntu that I'd like to compile for windows. Right now I compile and run it with a makefile like this:
OBJECTS = main.o text.o object.o vector.o physics.o shapes.o target.o
run: all
./a.out
all: $(OBJECTS)
gcc $(OBJECTS) `sdl2-config --cflags --libs` -lSDL2_ttf -lSDL2_image -lm -ldl
main.o: main.c defs.h
gcc -c main.c `sdl2-config --cflags --libds` -lSDL2_ttf
text.o: text.c text.h defs.h
gcc -c text.c
object.o: object.c object.h defs.h
gcc -c object.c
vector.o: vector.c vector.h defs.h
gcc -c vector.c
physics.o: physics.c physics.h defs.h
gcc -c physics.c
shapes.o: shapes.c shapes.h defs.h
gcc -c shapes.c
target.o: target.c target.h defs.h
gcc -c target.c
clean:
rm *.o
I'd suggest quasi-msys2 cross-compilation environment (I'm the author).
From the first glance, your makefile should work in it with minimal changes:
sdl2-config doesn't work there (which is a minor defect), but pkg-config does.
Replace sdl2-config with pkg-config sdl2 SDL2_image SDL2_ttf (followed by --libs and/or --cflags).
Then -lSDL2_ttf -lSDL2_image should be removed, since pkg-config is going to output those anyway.
Note that pkg-config ... --libs should be used when linking, and pkg-config --cflags should be used when compiling (same with sdl2-config).
-ldl should be removed. -lm is unnecessary, but should be harmless.
gcc should be replaced with $CC to pick up the compiler from the environment variable.
While this doesn't affect correctness, manually specifying .h dependencies in makefiles is error-prone and tedious. Instead you should be compiling with -MMD -MP flags, to automatically generate the dependencies.
Since removing the dependencies makes all your .o recipes look very similar, you can deduplicate them into a single recipe:
%.o : %.c
$CC -c $< -MMD -MP
-MMD -MP is going to produce .d files (tiny makefile pieces), which need to be included using -include $(OBJECTS:.o=.d).
With those fixes, the makefile should work in quasi-msys2, except that the resulting executable is going to be called a.exe and not a.out...
# We're going to cross-compile with Clang. Install Clang, LLD, Wine. Then...
# Clone the repo
https://github.com/HolyBlackCat/quasi-msys2
cd quasi-msys2
# Install the necessary packages
make install _gcc _SDL2 _SDL2_image _SDL2_ttf
# Open the cross-compilation shell
# Among other things, this sets `CC` to a wrapper for Clang that invokes it
# with the right flags, and sets env variables for `pkg-config` to find the
# newly installed libs.
env/shell.sh
Then just run make as usual.
Related
I have just started learning about makefile files. I created a program that consists of two functions and wanted to use a makefile to put it all together. This is my file:
#Makefile
all: main
main: main.o find_root.o
clang -o main main.o find_root.o
main.o: main.c
clang -c -Wall --pedantic -std=c11 main.c -lm
find_root.o: find_root.c
clang -c -Wall --pedantic -std=c11 find_root.c -lm
clean: rm -f main *.o*
However, when I run this, I get an error - "undefined reference to cos". I am using the cosine functions in my program, but I have already linked the library to the compilation of those two files. I thought about adding "-lm" to the first clang option as well. This led to no errors, but it made a warning instead - saying that "-lm linker is unused". What should I change in my file?
The "-lm" is a linker option but you have only included it in your compilation rule (main.o: main.c). You need to include it in your linker rule (main: main.o find_root.o).
As it stand the -lm option is ignored during compilation and missing during linking.
The linker flags aren't used when compiling, but when linking, so the command for the main rule should have -lm, rather than the command for the *.o files.
Better would be just to set the appropriate variables, and let Make use its built-in rules:
#Makefile
LDLIBS += -lm
CFLAGS += -Wall --pedantic -std=c11
C = clang
all: main
main: main.o find_root.o
$(LINK.c) $^ $(LDLIBS) -o $#
clean:
$(RM) main *.o *~
i'm writing an emulator program and I need a graphics library. I have 4 files, the graphics library GLWF3 is installed in my includes folder. Im using MacOs Yosemite. I can't figure out how to get the makefile working though to include the glfw3 library. Thanks in advance!
Also note the only file including GLWF3 is graphics.h
Makefile
OBJ = graphics.o chip8.o
emulator: $(OBJ)
gcc -o emulator $(OBJ)
graphics.o: graphics.c graphics.h
gcc -c graphics.c
chip8.o: chip8.c chip8.h
gcc -c chip8.c
clean:
rm -f $(OBJ) emulator
To build with a given library, you have to:
tell the compiler how to find library header file
tell the linker which what library at must link.
Compilation
To tell where are the headers, you must pass a -I/path/to/dir option to gcc. Often, the make CFLAGS variable is used to do so:
CFLAGS= -I/path/to/glfw/include/dir
graphics.o: graphics.c graphics.h
gcc -c graphics.c $(CFLAGS)
chip8.o: chip8.c chip8.h
gcc -c chip8.c
Link
To tell linker what library to use, and where it is located, option -L/path/to/sofile and -lthelib are used. Usually in LDFLAGS variable:
Warning: The -l options must come after the files to link (*.o files)
LDFLAGS = -L/path/to/libglfw/lib/dir
# if the so file name is "libglfw3.so", the "-l" option must be "-lglfw3"
LDFLAGS += -lglfw3
emulator: $(OBJ)
gcc -o emulator $(OBJ) $(LDFLAGS)
pkg-config
To not to have to deal with paths, you can use pkg-config tool: This tool will help you to set CFLAGS and LDFLAGS variables. See here for installation instructions..
Hence, you makefile will looks like:
OBJ = graphics.o chip8.o
# calling program "pkg-config" and store result in CFLAGS variable
CFLAGS = $(shell pkg-config --cflags glfw3)
# calling program "pkg-config" and store result in LDFLAGS variable
LDFLAGS = $(shell pkg-config --ldflags glfw3)
emulator: $(OBJ)
gcc -o emulator $(OBJ) $(LDFLAGS)
graphics.o: graphics.c graphics.h
gcc $(CFLAGS) -c graphics.c
chip8.o: chip8.c chip8.h
gcc $(CFLAGS) -c chip8.c
clean:
rm -f $(OBJ) emulator
I have built OpenSSL from source (an intentionally old version; built with ./config && make && make test) and would prefer to use what I have built without doing make install to link against my program.
The command that's failing is:
gcc -Wall -Wextra -Werror -static -Lopenssl/openssl-0.9.8k/ -lssl -lcrypto
-Iopenssl/openssl-0.9.8k/include -o myApp source1.o source2.o common.o`
And I receive a series of errors similar to:
common.c:(.text+0x1ea): undefined reference to `SSL_write'
This makes me think there's something funky with my OpenSSL. If I omit -Lopenssl/openssl-0.9.8k/ from my command, the error changes to being unable to:
/usr/bin/ld: cannot find -lssl
/usr/bin/ld: cannot find -lcrypto
Am I compiling OpenSSL incorrectly? Or how should I best resolve this?
Silly "Linux-isms" strike again! Apparently, I need to change my command such that the -L and -l stuff is at the end like (despite what man gcc seems to indicate):
gcc -Wall -Wextra -Werror -static -o myApp source1.o source2.o common.o -Lopenssl/openssl-0.9.8k/ -lssl -lcrypto -Iopenssl/openssl-0.9.8k/include
Why don't you want to use make install? It can copy generated binaries in the directory you want if you previously passed it to ./configure --prefix $HOME/target_library_install_directory
If you used this trick with every library you build and install, you could then add the target directory to the LIBRARY_PATH environment variable and avoid using -L option.
If you use Autotools, or you are building an Autools project like cURL, then you should be able to use pkg-config. The idea is the Autotools package will read OpenSSL's package configuration and things will "just work" for you.
The OpenSSL package configuration library name is openssl.
You would use it like so in a makefile based project.
%.o: %.c
$(CC) -o $# -c `pkg-config --cflags openssl` $^
target: foo.o bar.o baz.o
$(CC) -o $# `pkg-config --libs openssl` $^
Also see How to use pkg-config in Make and How to use pkg-config to link a library statically.
Another approach is to use pkg-config to preserve compatibility. This is an example of makefile when needs to link OpenSSL.
CC = gcc
CFLAGS = \
-I. \
-D_GNU_SOURCE=1
LDFLAGS = `pkg-config --libs inih`
LDFLAGS += `pkg-config --libs libcurl`
LDFLAGS += `pkg-config --libs liburiparser`
LDFLAGS += `pkg-config --libs openssl`
# Executable
foo: foo.o
$(CC) -o $# $^ $(LDFLAGS)
foo.o: foo.c
$(CC) -c $(CFLAGS) $< -o $#
I am working on a C project for Linux-environment (compiled with gcc). I am using two libraries:
SDL image (source is stored at the directory SDL_img).
SDL TTF (source is stored at the directory SDL_ttf).
My CFLAGS variable:
CFLAGS = -std=c99 -pedantic-errors -Wall -g -lm `sdl-config --cflags` -ISDL_img -ISDL_ttf
As you can see, I am including those two library-directories.
My gcc command include the following:
`sdl-config --libs` -lSDLmain -lSDL -lSDL_img -lSDL_ttf
Finally, in my project I have the following includes:
#include "SDL_ttf.h"
#include "SDL_image.h"
For some reason, I get errors of the type:
undefined reference to 'IMG_Load'
Why?
EDIT:
all: Chess.o Commons.o Console.o Controls.o Coords.o File.o GameState.o GUI.o Keyboard.o List.o Minimax.o Move.o Piece.o SettingsState.o Slots.o Square.o Str.o
gcc $^ -lm -std=c99 -pedantic-errors -g -o Chess `sdl-config --libs` -lSDLmain -lSDL -lSDL_img -lSDL_ttf
Just cd to those src/SDL_xxx dirs and do make to build those libraries and then set the correct -L and -I. It failed on linking so the -I is "good" but your path to your libraries is incorect
basically linker is now searching its paths to find libSDL_img and libSDL_ttf then it also searches /usr/lib/x86_64-linux-gnu and it still can not find it, that is why you are getting undefined referecne.
To fix this: first build those SDL_xxx and then search where are those libraries and pass somethig like this along with other to gcc:
-Lsrc/SDL_img/lib -lSDL_img -Lsrc/SDL_ttf/lib -lSDL_ttf
So I tried to recompile one of my projects from a few weeks ago and to my surprise I keep receiving an error one on it. I used MinGW to compile it originally and Eclipse CDT. I have -Wall flag enabled on GCC so I assumed if it was a problem with the code I would have a more useful information than a make error 1 being thrown. As such, I suspect that the issue could lie in how I formatted the make file. Luckily, I did compile the project when I push the commits last time and the binaries are still in the repo. Nevertheless, I would appreciate some help so that I can continue to improve
the project.
Edit: when I do -all, it just refuses to compile.
Here is the makefile. I hope it is a simple as me following some incorrect syntax:
CC=gcc -I../Include -L..\Lib
override CFLAGS+=-Wall -O3 #$(shell pkg-config --cflags fftw3)
#override LDFLAGS+=#$(shell pkg-config --libs fftw3 glib-2.0) -lm
.PHONY: all clean
all: lvdoenc lvdodec
lvdoenc: lvdoenc.o lvdomain.o
$(CC) $(CFLAGS) -o $# $^ $(LDFLAGS) -I../Include -L../Lib -lfftw3
lvdodec: lvdodec.o lvdomain.o
$(CC) $(CFLAGS) -o $# $^ $(LDFLAGS) -I../Include -L../Lib -lfftw3
%.o: %.c
$(CC) -c $(CFLAGS) -o $# $^
lvdoenc.c: lvdocommon.h
lvdodec.c: lvdocommon.h
clean:
rm -f lvdoenc lvdodec lvdomain.o lvdoenc.o lvdodec.o
Here is a link to my repo:
https://github.com/Skylion007/LVDOWin
Update: Using some of the answers I have confirmed that it is GCC that is exiting with an error 1 and I cannot figure out why.
Update2: It's not printing anything to syserr.
Without a transcript of make's output, when you run it, I can't see why GCC should fail silently, but I can see at least two problems with your makefile:
Since you state that you are using MinGW, your target platform must be MS-Windows, on which executable files should be qualified by a .exe extension; thus, your all: lvdoenc lvdodec rule is malformed; it should, at the very least be all: lvdoenc.exe lvdodec.exe[1], (or better, for portability all: lvdoenc$(EXEEXT) lvdodec$(EXEEXT), where you define EXEEXT = .exe for Windows, and leave EXEEXT undefined, or defined to be nothing, for platforms which don't require the extension).
Your two rules lvdoenc.c: lvdocommon.h and lvdodec.c: lvdocommon.h are obviously incorrect; the .c files don't depend on the .h, but their respective .o files do. Thus, these two rules should be lvdoenc.o: lvdocommon.h and lvdodec.o: lvdocommon.h respectively.
[1] Of course, you then also need to correctly refer to these two "goals" respectively, as lvdoenc.exe and lvdodec.exe, (or lvdoenc$(EXEEXT) and lvdodec$(EXEEXT)), consistently, throughout the makefile.
There are a few other constructs, within your makefile, which I consider questionable: CC shouldn't really be defined, with the -I../Include or -L..\Lib, (and why inconsistently / in the former, but \ in the latter? Both should be /). Conventionally, -I ... belongs in CPPFLAGS, and -L ... in LDFLAGS, with both CFLAGS and CPPFLAGS passed to the compiler, and normally all of CFLAGS, CPPFLAGS, and LDFLAGS passed to the compiler driver, when invoking the linker, (although, as others have noted in comments, the -I ... settings are strictly necessary when compiling .c to .o, while the -L ... settings are required only in the linking phase).
the following makefile is more in line with what you need for your project.
However, it does not use:
#$(shell pkg-config --libs fftw3 glib-2.0)
which you will need to re-add.
notice the usage of ':=' when defining macros, so the macro only needs to be evaluated once, rather than every time it is referenced.
the paths for the SHELL macro and the CC macro may need to be modified for your system.
SHELL := /usr/bin/sh
CC := /usr/bin/gcc
#CFLAGS := -c -Wall -Wextra -pedantic -std=c99 -O3 #$(shell pkg-config --cflags fftw3)
CFLAGS := -c -Wall -Wextra -pedantic -std=c99 -O3
# override LDFLAGS+=#$(shell pkg-config --libs fftw3 glib-2.0) -lm
LDFLAGS :=
SRCS := $(wildcard *.c)
ENCOBJS := lvdoenc.o lvdomain.o
DECOBJS := lvdodec.o lvdomain.o
.PHONY: all clean
all: lvdoenc lvdodec
lvdoenc: $(ENCOBJS)
$(CC) $(LDFLAGS) -o $# $(ENCOBJS) -L../Lib -lfftw3 -lm
lvdodec: $(DECOBJS)
$(CC) $(LDFLAGS) -o $# $(DECOBJS) -L../Lib -lfftw3 -lm
%.o:%.c lvdocommon.h
$(CC) -c $(CFLAGS) -c $< -o $# -I../Include
clean:
rm -f lvdoenc lvdodec lvdomain.o lvdoenc.o lvdodec.o
Apparently, all that was the cause was that I had uninstalled the 64bit version of MinGW and tried to switch to the 32bit version of MinGW. Unfortunately, some of the libraries would not compile in the 32bit version so I just used MinGW-w instead to solve this problem. It turns out GCC was not starting due to a linker error, but this error was not proportionating and could not be discovered until I tried to run it from the Windows terminal. I am still in the process of solving it and will update this answer when I have fully solved the issue.
Had the same problem while tried to compile my project with make from MSys. Accidentally problem had been solved, after I added a quotes to gcc input and output files in the makefile. I don't know how it works, but hope that it will help someone else.
So in the TS example code should look like this
%.o: %.c
$(CC) -c $(CFLAGS) -o "$#" "$^"
PS: had no problems with building project from ubuntu terminal though, so maybe it's just a msys problem.