Working Set
Here I collect all kinds of compiling, linking specific snippets and notes.
Building 32bit and 64bit libraries
Most libraries still use autotools as their build system a typical build is done by executing the following commands:
$ ./configure --prefix=/path/to/install [OPTION=VALUE] $ make $ mak install
If you want to specify if you want to build a 32bit or 64bit you
want to set the CFLAGS, CXXFLAGS and LDFLAGS options. The CFLAGS
and CXXFLAGS that are generally used to 32bit and 64bit are
-m32
and -m64
respectively. The linker wants some other option
and not all linkers use the same. The LDFLAGS are used for the linker
options and (on mac) you can pass -arch i386
or -arch x86_64
.
To build for 32bit you can use something like:
$ ./configure --prefix=/some/path CFLAGS="-m32" CXXFLAGS="-m32" LDFLAGS="-arch i386" $ make $ make install
To build for 64bit you can use something like:
$ ./configure --prefix=/some/path CFLAGS="-m64" CXXFLAGS="-m64" LDFLAGS="-arch x86_64" $ make $ make install
The --with-* flag
Quite some autotools libraries allow you to specify some --with-[libname]
flags. The
value you should set is the path to the directory which contains the include/
and
lib
sub directories of the lib you want to use.
Library link order with LDFLAGS
You can set the LDFLAGS environment variable when you compile with e.g. autotools. If you want to use a custom search directory for libraries the given search directories are searched first; before the linker build in search dirs.
CMake, using a macro and pass a list into it
macro(my_macro list) foreach(entry ${list}) message("- ${entry}") endforeach() endmacro() set(myvar filea.cpp fileb.cpp filec.cpp )
CMake check if variable refers to file or directory
foreach(lib ${streamer_libraries}) if(NOT IS_DIRECTORY ${lib}) install(FILES ${lib} DESTINATION lib) endif() endforeach() # note the "" around ${myvar} my_macro("${myvar}")
CMake set file specific properties
if(APPLE) set(of_objc_sources ${of_base_dir}/app/ofAppGLFWWindow.cpp ${of_base_dir}/video/ofQTKitGrabber.mm ${of_base_dir}/video/ofQTKitPlayer.mm ${of_base_dir}/video/ofQTKitMovieRenderer.m ${of_base_dir}/utils/ofSystemUtils.cpp ) set_source_files_properties(${of_objc_sources} PROPERTIES COMPILE_FLAGS "-x objective-c++") endif()
CMake set definitions for a specific target
set_target_properties(broadcaster${debug_flag} PROPERTIES COMPILE_DEFINITIONS "USE_AUDIO=0")
CMake check if install prefix is set
if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) message(FATAL_ERROR "Set install dir ${install_dir}") set(CMAKE_INSTALL_PREFIX ${install_dir}) endif()
CMake fix dylib loading
if(APPLE) add_custom_command(TARGET ${app_name} POST_BUILD COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change "./libfmodex.dylib" "@executable_path/libfmodex.dylib" $<TARGET_FILE:${app_name}>) endif()
CMake set rpath on Linux
When you want to link with a dynamic library and you want to
keep the .so file near the executable you can use the CMAKE_INSTALL_RPATH
command
on Linux. This will set a path that the executable will use to look for the dynamic
library. You can use a value of $ORIGIN
which means that the RPATH is contains
a relative path.
set(CMAKE_INSTALL_RPATH "$ORIGIN")
CMake and generated files (idl files)
For a project I had to use .idl files with CMake. An .ild file is used on Windows with the midl.exe compiled (or maybe other systems too, but this is how I got to know about these idl files). The midl.exe compiler created a .c and a .h file which I then had to use in my project.
So the first step in the compile process was to create a .c and .h from these .idl file. Then I had to add this file to my project sources. To do this you need to do the following:
- use
add_custom_target()
to add a midl.exe compile command - set the GENERATED flag of the generated files to true (in my case the .c output)
- add the generated file to your application source files
- add a dependency so that the custom target will be executed before your application target
# midl.exe only works when the output directory (-out) actually exists add_custom_target(DeckLinkAPI COMMAND midl.exe -nologo -W1 -char signed -env win32 -out "${vd_sdk_dir}" -h DeckLinkAPI.h /iid DeckLinkAPI_i.c ${vd_sdk_dir}/idl/DeckLinkAPI.idl ) set_source_files_properties(${vd_sdk_dir}/DeckLinkAPI_i.c PROPERTIES GENERATED TRUE) # add the file to the sources of may app set(my_app_source_files ${vd_sdk_dir}/DeckLinkAPI_i.c # we've set the GENERATED flag to true, so cmake won't complain when it cannot find it ) add_dependencies(MY_APP_TARGET DeckLinkAPI)
CMake append to list
list(APPEND list_name "${var}") list(APPEND nn_libs ${fr_cs} ${fr_cf})
CMake Parallel iteration
set(list1 1 2 3 4 5) set(list2 6 7 8 9 0) list(LENGTH list1 len1) math(EXPR len2 "${len1} - 1") foreach(val RANGE ${len2}) list(GET list1 ${val} val1) list(GET list2 ${val} val2) message(STATUS "${val1} ${val2}") endforeach()
CMake create application bundle
cmake_minimum_required(VERSION 2.8) project(VideoStreamer) add_executable(video_streamer MACOSX_BUNDLE main.cpp) install(TARGETS video_streamer BUNDLE DESTINATION bin)
CMake install library, include files and executables
install(TARGETS ${vs_lib_name} ARCHIVE DESTINATION lib) install(DIRECTORY ${vs_inc_dir}/ DESTINATION include) install(TARGETS ${gr_app_name} RUNTIME DESTINATION bin BUNDLE DESTINATION bin) install(FILES ${files} DESTINATION include)
CMake set paths for find_package
Most cmakefiles use the find_package
feature to locate libraries. You can
use the CMAKE_PREFIX_PATH
to tell cmake in what directories it should look
for files. Use the "top" level directory (so the parent of include, lib etc..).
cmake -DCMAKE_PREFIX_PATH="/path/one;/path/two/" ../
CMake add icon and create OSX bundle
This example below will use the file bin/data/images/icon.icns
as the icon
for the application bundle. It's important that you name it icon.icns
because
that's the value we use for MACOSX_BUNDLE_ICON_FILE
. We tell cmake that the
icon needs to be copied into the Resources
directory. Make sure that
the icon file is also part of the add_executable()
.
if (APPLE) set(osx_bundle "MACOSX_BUNDLE") set(MACOSX_BUNDLE_ICON_FILE icon.icns) set(icon_file ${CMAKE_INSTALL_PREFIX}/bin/data/images/icon${debug_flag}.icns) set_source_files_properties(${icon_file} PROPERTIES MACOSX_PACKAGE_LOCATION Resources) endif() add_executable(ApplicationName ${osx_bundle} ${icon_file})
PkgConfig: link with static libaries
pkg-config --static
CMake check if library exists
Sometimes it's usefull to know if a specific library exists and only add it to the linker libraries when it was found:
include(CheckLibraryExists)
# LibWebSockets required us to link with libcap when it's available.
CHECK_LIBRARY_EXISTS(cap cap_set_flag "" HAVE_LIBCAP)
if (HAVE_LIBCAP)
find_library(LIBCAP_LIBRARIES NAMES cap)
list(APPEND lc_libs ${LIBCAP_LIBRARIES} )
endif()
Mac OSX dynamic libraries
On windows it's quite common to have dll files in the same directory as the executable;
when the application is started the executable directory is used to search for dlls. On
mac this works a bit different, but you can get the same behavior by setting the
path to the dylib
to @executable_path
using the install_name_tool
. Below myapp
is
the executable (not a application bundle)
innstall_name_tool -change libmysqlclient.18.dylib @executable_path/libmysqlclient.18.dylib myapp
when you now put libmysqlclient.18.dylib
in the same directory as myapp
it will find that
dylib in the executable path.
Build a release version with cmake
cmake --build . --target install --config Release
msbuild.exe quirks
msbuild.exe can be used to build Visual Studio solutions and projects files from the command line. Though the web is full with contradiction and/or examples which seem to work only for specific versions; these are some example that worked for me using msbuild 4.0.30319.1.
Adding include paths
msbuild.exe should use the INCLUDE
environment variable for extra search paths. When
I was trying to compile libflac this didn't seem to work; but it seems to work for
libopenssl. Instead of INCLUDE
I used the environment variable CL
which seems
to work with libflac. You can use the LINK
environment variable to link with a
specific library.
SET CL=/IC:\roxlu\extern\win-vs2010-i386\include SET LINK=C:\roxlu\extern\win-vs2010-i386\lib\libogg.lib
Debug information
The easiest way to create a debug library that contains debug symbols it to make
sure that your debug format uses /Z7
, this will put all debug info in the .obj
file and so in the generated library.
cygwin / mingw
Cygwin is a fantastic suite of utils which gives you the feel of linux on windows. You can use sh/bash/configure/make etc.. It has also support for the gcc compiler. Besides their own gcc compiler it features the mingw32-w64 (which is completely different then the mingw32.org, outdated, legacy version). If you need to compile libraries which only support the autotools toolchain, use the mingw compiler; only pure windows libs will be created then.
Specificy you want to use the mingw32-w64 compiler
# make sure to set the --host flag to `i686-w64-mingw32` ./configure --host=i686-w64-mingw32
Windows, MingW and import libraries
When you compile a library with mingw and you want to use it together with MSVC, you need to generate a .lib file using the LIB util on windows. Else you'll get lots of wierd problems. See the x264 project and this blog post
Inspect RPATH on Linux
objdump -p your_app_name | grep -i "RPATH"
List dynamically linked libraries on Linux
ldd your_app_name
See what DLLs are used by your app
When you want to inspect your executable and see what DLLs it
uses, then a dependency checker is a must. An amazing tool is
Dependencies. Download
it and run DependenciesGui.exe
.
Int the past Dependency Walker has been an extremely valuable tool that you can use while diving into compiling and linking issues. Though recently it didn't really work well on Windows 10 with VS2019.
Determine if a Windows Library is 32bit or 64bit
Use the dumpbin /headers [yourlib]
command and check the machine value.
Or dumpbin /headers [yourlib] | findstr /R /C:"machine"
.
32 BIT:
dumpbin /headers glfw3.lib | more Microsoft (R) COFF/PE Dumper Version 10.00.30319.01 Copyright (C) Microsoft Corporation. All rights reserved. Dump of file glfw3.lib File Type: LIBRARY FILE HEADER VALUES 14C machine (x86) 2F number of sections 52EE3A0E time date stamp Sun Feb 02 12:29:02 2014 1DA2 file pointer to symbol table A5 number of symbols 0 size of optional header 0 characteristics
64 BIT:
dumpbin /headers glfw3.lib | more Microsoft (R) COFF/PE Dumper Version 10.00.30319.01 Copyright (C) Microsoft Corporation. All rights reserved. Dump of file glfw3.lib File Type: LIBRARY FILE HEADER VALUES 8664 machine (x64) 4E number of sections 52EE3A2F time date stamp Sun Feb 02 12:29:35 2014 26E8 file pointer to symbol table 110 number of symbols 0 size of optional header 0 characteristics
Determine if a DLL is Debug or Release
One solution you can use is dumpbin /imports [yourdll.dll]
, one
of the lines you'll see is MSVCR120D.dll
for debug dlls or,
MSVCR120.DLL
for release builds.
Debug:
MSVCR120D.dll 180098208 Import Address Table 180098920 Import Name Table 0 time date stamp 0 Index of first forwarder reference
Release:
MSVCR120.dll 18002A0D0 Import Address Table 1800336D8 Import Name Table 0 time date stamp 0 Index of first forwarder reference
Determine the used runtime library on Windows
Use the dumpbin /directives [yourlib.lib]
. For more
information about the the runtime libraries, see this
page
dumpbin /directives glfw3.lib | more Microsoft (R) COFF/PE Dumper Version 10.00.30319.01 Copyright (C) Microsoft Corporation. All rights reserved. Dump of file glfw3.lib File Type: LIBRARY Linker Directives ----------------- /DEFAULTLIB:"MSVCRT" /DEFAULTLIB:"OLDNAMES"
Determine debug or release build on Windows
This is similar to determining which runtime library is used. If you
execute the dumpbin /directives [yourlib.lib]
and you see e.g.
MSVCRTD
it means it links against the debug runtime. When you see
MSVCRT
it links against the release version.
Check invalid memory reads and writes.
On Mac you can compile with clang using the -fsanitize=address
flag.
You just enable this flag and then run the application as normal. When
a invalid memory read or write happens the application will crash with
a log which shows exactly what happened. Use this to add it to
your CMakeLists file.
set (CMAKE_CXX_FLAGS "-fsanitize=address ${CMAKE_CXX_FLAGS}")