Can I use CMake to compile a program in stages? - cmake

I'm using the LLVM compiler to perform some analyses. I also have a test application I've written that I build using CMake. I'd like to compile the test application in stages:
Compile all source files of the test application to LLVM bitcode.
Link all of the bitcode files together using llvm-link.
Compile this linked bitcode file down into an actual binary (using an extra flag to run my analyses).
As an example, if I had a program test comprised of 3 files, foo.c, bar.c, and bar.h:
Normal compilation:
clang -I. -c foo.c // generates foo.o
clang -I. -c bar.c // generates bar.o
ld -lc -lgcc -o test foo.o bar.o // links foo.o and bar.o
Bitcode compilation & linking:
clang -I. -c -emit-llvm foo.c // generates foo.bc
clang -I. -c -emit-llvm bar.c // generates bar.bc
llvm-link -o test.bc foo.bc bar.bc // links foo.bc and bar.bc
clang -I. -o test test.bc // generates test
As I said, I've already written CMake files that build and compile the test application normally (i.e., in a single stage).
Is it possible, through some combination of adding custom commands and/or targets, to achieve such a thing? Or should I continue with my current approach of using bash/Python scripts to run this process?

Related

Is -std=c++2a necessary at link stage as well?

If I compile in two stages, using a particular language standard:
g++ -std=c++2a -c file1.cpp #compile source files
g++ -std=c++2a -c file2.cpp
g++ -std=c++2a file1.o file2.o -o program #link 'em
...can I leave the -std=c++2a out of the link command, or is it sometimes needed?
Version is gcc 10.
I guess you are compiling on Linux with a recent GCC. Be sure to read more about C++ and about your particular compiler (i.e. GCC 9 is not the same as GCC 10). Check with g++ --version what it is.
In practice you want to compile with warnings and debug information (in DWARF for GDB inside your ELF object files and executables), so use
g++ -std=c++2a -Wall -Wextra -g -c file1.cpp
and likewise for file2.cpp
Later (once your program is correct enough, e.g. has few bugs) you could want to ask the compiler to optimize it. So you could use
g++ -std=c++2a -Wall -Wextra -O3 -g -c file1.cpp
Practically speaking, you'll configure your build automation tool (e.g. GNU make or ninja) to run your compilation commands.
In rare cases, you could want to use link time optimizations. Then you need to both compile and link with g++ -std=c++2a -Wall -Wextra -O3 -g -flto and perhaps other options.
Be aware that link time optimization could almost double your build time.
You could also be interested by static analysis options of GCC 10 (or even by writing your own static analysis using GCC plugins).

CMake on Cygwin with clang not creating expected dll.a

I'm building a shared library and an application using that lib on Cygwin. With GCC CMake creates a .dll.a to use when linking. Switching to clang I get
[ 34%] Built target xxx_shared
make[2]: *** No rule to make target 'src/libxxx.dll.a', needed by 'xxx.exe'. Stop.
Is this a bug in the clang CMake extension?
I'm using cmake --version 3.3.2
Yes, it seems to be a bug in CMake. Running make VERBOSE=1 reveals that with GCC:
/usr/bin/c++.exe -g -shared -Wl,--enable-auto-import -o XXX -Wl,-Bstatic -lm -Wl,-Bdynamic -lstdc++ -lcygwin -ladvapi32 -lshell32 -luser32 -lkernel32
while with clang:
/usr/bin/clang++ -fPIC -g -shared -o XXX -Wl,-Bstatic -lm -Wl,-Bdynamic -lstdc++ -lcygwin -ladvapi32 -lshell32 -luser32 -lkernel32
So it seems that somehow clang++ does not get the -Wl,--enable-auto-import flag. Manually running the corrected clang++ command correctly creates the expected .dll.a allowing the rest of the build to proceed as expected.
Haven't figured out why this happens yet, though. At this point I can't decipher CMakes platform extensions, which seems to set this for GCC.
Update: I've reported this here.

Cross-platform static-linking SDL2

I'm building an SDL2/C++ program that needs to be portable to Windows, Mac, and Linux machines which may not have SDL installed.
I've read that static linking is the solution, but I'm not very good with compiling and don't know how to static link.
My program relies only on SDL2, GLU, and OpenGL. I'm compiling C++ with either MinGW (on Windows 8.1) or gcc (on Ubuntu 14.04) -- both of these OS's have SDL installed natively.
Here is my current makefile, derived from a sample makefile given to me by a professor of mine:
# Executable/file name
EXE=experiment
# MinGW
ifeq "$(OS)" "Windows_NT"
CFLG=-O3 -Wall -DUSEGLEW
LIBS= -lSDL2 -lglu32 -lopengl32
CLEAN=del *.exe *.o *.a
else
# OSX
ifeq "$(shell uname)" "Darwin"
CFLG=-O3 -Wall -Wno-deprecated-declarations
LIBS=-framework SDL2 -framework OpenGL
# Linux\Unix\Solaris
else
CFLG=-O3 -Wall
LIBS= `sdl2-config --cflags --libs` -lGLU -lGL -lm
endif
# OSX\Linux\Unix\Solaris
CLEAN=rm -f $(EXE) *.o *.a
endif
# Dependencies
$(EXE).o: $(EXE).cpp FORCE
.c.o:
gcc -c -o $# $(CFLG) $<
.cpp.o:
g++ -std=c++11 -c -o $# $(CFLG) $<
# Link
$(EXE):$(EXE).o
g++ -std=c++11 -O3 -o $# $^ $(LIBS)
# Clean
clean:
$(CLEAN)
# Force
FORCE:
To link with static library you either specify path to library file
gcc -o out_bin your_object_files.o path/to/lib.a -lfoo
or ask linker to use static version with -Bstatic linker flag. Usually you'll want to reset linking back to dynamic for the rest of the libraries, e.g. for static SDL2 and GLU but dynamic GL:
gcc -o out_bin your_object_files -Wl,-Bstatic -lSDL2 -lGLU -Wl,-Bdynamic -lGL
That of course implies that static versions of libraries are present in library search path list (.a libs for gcc on all specified platforms, although MSVC uses .lib for static libraries).
However you usually don't really want to do that at all. It is common practice for software to either depend on some libs (widespread on linux, with packages and dependendices lists) or bring required libraries with it. You can just distribute SDL dynamic library with your program and load it with LD_LIBRARY_PATH or relative rpath.
Please also note that newer SDL2 implements dynamic loading of functions which provides a way to override SDL with user-specified dynamic library, even if linked statically.
It wasn't related directly to static linking. When static linking, I had to include all of SDL's dependency libraries. Turns out, having -mwindows causes console communication to fail.

EGL linker errors

I'm trying to link a really simple GLES2 & EGL program using g++ 4.9.1, on a Ubuntu Trusty system. I'm using the mesa libraries.
I'm getting linker errors for EGL functions:
test.cpp:(.text+0x342): undefined reference to `eglGetDisplay'
test.cpp:(.text+0x389): undefined reference to `eglInitialize'
test.cpp:(.text+0x40f): undefined reference to `eglCreateContext'
test.cpp:(.text+0x458): undefined reference to `eglCreatePbufferSurface'
test.cpp:(.text+0x49e): undefined reference to `eglMakeCurrent'
I am compiling test.cpp with
g++ -std=c++0x -Wall -Werror -lEGL -lGLESv2 -o test test.cpp
I've tried switching the order of libraries, which sometimes matters, but I get the same problem. Is there a library I'm missing here?
I've run readelf -Ws /usr/lib/x86_64-linux-gnu/mesa-egl/libEGL.so and all of the required functions are defined.
You should put libraries to the end of a command line
g++ -std=c++0x -Wall -Werror -o test test.cpp -lEGL -lGLESv2
I managed to fix this by compiling the C++ file to an object file, and then linking as a separate step. I'm not sure why this works, when the one-line compilation doesn't.
g++ -std=c++0x -Wall -Werror -c -o test.o test.cpp
g++ -o test test.o -lGLESv2 -lEGL
I've put the question to the community to try to figure out why: Single-command compile and link fails, separate steps work

How to convert Obj-C code into a library

I have 3 apps written in Obj-C that I want to modify and convert to libraries, so I can use them in a Monotouch app.
Where do I find docs that tell me how to take Obj-C code and turn it into libraries?
Imagine you have a file called lib1.m
You will first have to compile it as object code. For instance:
gcc -Wall -framework Cocoa -o lib1.o lib1.m
That will create lib1.o
Then you'll have to decide wether you want a static or dynamic library.
To build a static library, you'll need a library object first:
glibtool --quiet --mode=compile gcc -o lib1.lo -c lib1.c
Then you can create the static library from the library archive:
glibtool --quiet --mode=link gcc -o lib1.la -c lib1.lo
To build a dynamic library:
libtool -dynamic -flat_namespace -lSystem -undefined suppress -macosx_version_min 10.6 -install_name /usr/local/lib/lib1.dylib -o lib1.dylib lib1.o
Note that for dynamic libraries, you must provide the install path when creating the library.