Using external libraries with ocamlbuild - makefile

I'm trying to use ocamlbuild instead of make, but I'm unable to correctly link my object files with external .cma libraries. It seems like ocamlbuild tries to determine dependencies first and then ignores flags like -L/path/to/lib.cma. With make I was just passing all necessary directories with -I and -L flags to ocamlc, but these don't seem to work with ocamlbuild -- ocamlc keeps failing because it can't find necessary libraries.

You have at least 2 ways to pass your parameters to ocamlbuild for it to take your library in account:
You can use the command line parameters of ocamlbuild:
$ ocamlbuild -cflags '-I /path/to/mylibrary' -lflags '-I /path/to/mylibrary mylibrary.cma' myprogram.byte
Replace .cma by .cmxa for a native executable.
Use the myocamlbuild.ml file to let ocamlbuild "know" about the library, and tag the files which need it in the _tag file:
In myocamlbuild.ml:
open Ocamlbuild_plugin
open Command
dispatch begin function
| After_rules ->
ocaml_lib ~extern:true ~dir:"/path/to/mylibrary" "mylibrary"
| _ -> ()
In _tags :
<glob pattern>: use_mylibrary
The ocaml_lib instruction in myocamlbuild.ml tells the tool that the library named "mylibrary" (with specific implementations ending in .cma or .cmxa or others - profiling, plugins) is located in the directory "/path/to/mylibrary".
All the files corresponding to glob pattern in the project directory will be associated to the use of "mylibrary" by ocamlbuild, and compiled with the ad hoc parameters (so you don't need to worry about native or byte targets).
Ex:
<src/somefile.ml>: use_mylibrary
Note: if the library is located in the path known by the compiler (usually /usr/lib/ocaml or /usr/local/lib/ocaml), then the path prefix can be safely replaced by a + sign, so /usr/lib/ocaml/mylibrary becomes +mylibrary.

Related

cmake 'add_custom_command' to pre-process header files?

i'm working on a project requiring cmake. i'd like to add some custom rules to my makefile, but can't quite get my head around how to do it.
both c source files and header files are in the same directory. also in this same directory are a number of .def files, which are the sources for some of the header files #included in the source during compilation.
if i were to do this in a makefile, i'd use a simple rule like
.SUFFIXES: .def
.def.h:
$(PREPROC) $< > $#
how can i do this with cmake ??
i've tried various permutations of the following, both with and without cmake working directory specifications :
add_custom_command(
OUTPUT vvr_const.h
PRE_BUILD
COMMAND preproc vvr_const.def > vvr_const.h
DEPENDS vvr_const.def
)
add_custom_target(vvr_const.h DEPENDS vvr_const.def)
but the header file isn't generated by the time the c source file is compiled, so the compile fails. i've also tried a variation where i replace the last line above with
set_property(SOURCE main.c APPEND PROPERTY OBJECT_DEPENDS vvr_const.h)
in this case, the header file is correctly generated in advance, but make can't find it, and complains that there's no rule to make the target .h.
ideally this would be a general rule, like the make rule above, but i'm not opposed to making a separate rule for each of the .def files if that's what it takes.
cheers.
There are 2 problems with the add_custom_command approach you present:
You did not specify a working directory; by default the command is run in the build directory, not in the source directory.
You rely on shell functionality here (the redirect to a file). Even though this probably still works. You should go with an approach that does not rely on the shell.
To solve issues 1 and 2 I recommend creating a seperate cmake script file receiving the absolute paths to input and output files and using those in the custom command. This allows you to use execute_process to specify the file to write without relying on the platform.
preprocess_def.cmake
# preprocess def file
# parameters INPUT_FILE and OUTPUT_FILE denote the file to use as source
# and the file to write the results to respectively
# use preproc tool to get data to write to the output file
execute_process(COMMAND preproc "${INPUT_FILE}"
RESULT_VARIABLE _EXIT_CODE
OUTPUT_FILE "${OUTPUT_FILE}")
if (_EXIT_CODE)
message(FATAL_ERROR "An error occured when preprocessing the file ${INPUT_FILE}")
endif()
CMakeLists.txt
set(_INPUT_FILE "${CMAKE_CURRENT_SOURCE_DIR}/vvr_const.def")
set(_OUTPUT_FILE "${CMAKE_CURRENT_SOURCE_DIR}/vvr_const.h")
# not necessary to use build event here, if we mark the output file as generated
add_custom_command(OUTPUT "${_OUTPUT_FILE}"
COMMAND "${CMAKE_BUILD_TOOL}" -D "OUPUT_FILE=${_OUTPUT_FILE}" -D "INPUT_FILE=${_INPUT_FILE}" -P "${CMAKE_CURRENT_SOURCE_DIR}/preprocess_def.cmake"
DEPENDS "${_INPUT_FILE}")
add_executable(my_target vvr_const.h ...)
set_source_files_properties(vvr_const.h PROPERTIES GENERATED 1)
Documentation from cmake:
PRE_BUILD
On Visual Studio Generators, run before any other rules are executed within the target. On other generators, run just before PRE_LINK commands.
So possibly your command is just running too late.

Set autotools library filename and reference it later on

I'm using autotools to build a library which will later be loaded by another program. This library has to have a .so extension to it regardless of the platform I'm on (this is a requirement imposed by the program loading it), and I'd also like it to not have a version specifier. How can I set the output name of such a library?
This is what Makefile.am looks like
lib_LTLIBRARIES = mylib.la
mylib_la_SOURCES = mylib.c
mylib_la_CPPFLAGS = $(LTDLINCL)
mylib_la_CFLAGS = $(CFLAGS) $(LIBFFI_CFLAGS)
LDADD = $(LIBLTDL) -dlopen self
Reading through the libtool manpage, it seems I need to set -install_name, but I don't see it referenced in the generated Makefile anywhere.
I also need to be able to reference this library's output directory elsewhere in the Makefiles (for testing purposes), is there a variable containing its basename or full path?
How can I set the output name of such a library?
The output name of the library will be the name given in lib_LTLIBRARIES without the suffix .a. It will generate by default a shared library - .so. Thus, you do not need to specify anything else.
I also need to be able to reference this library's output directory elsewhere in the Makefiles (for testing purposes), is there a variable containing its basename or full path?
The variable $(libdir) or #libdir# in the Makefile will point to the full path of the library directory.

The -l option in GCC

I have just begun reading the book Advanced Programming in Unix Environment and try to compile the first example code, just the same as in this question.
Although the problem for the compilation is solved using the command,
gcc -o myls myls.c -I SCADDRESS/include/ -L SCADDRESS/lib/ -lapue
I looked it up in the GCC manual, but what does the GCC option -lxxx mean? Where xxx stands for the base name of a header file (in this case, it's apue.h). According to the manual, xxx should be some library files, either end with .so for shared object files, or with .a for static libraries.
This is documented in ยง2.13 "Options for Linking" in the GCC manual:
-llibrary
Search the library named library when linking.
It makes a difference where in the command you write this option; the
linker searches processes libraries and object files in the order they
are specified. Thus, `foo.o -lz bar.o' searches library `z'
after file `foo.o' but before `bar.o'. If `bar.o' refers
to functions in `z', those functions may not be loaded.
The linker searches a standard list of directories for the library,
which is actually a file named `liblibrary.a'. The linker then uses this file as if it had been specified precisely by name.
The directories searched include several standard system directories
plus any that you specify with `-L'.
Normally the files found this way are library files--archive files
whose members are object files. The linker handles an archive file by
scanning through it for members which define symbols that have so far
been referenced but not defined. But if the file that is found is an
ordinary object file, it is linked in the usual fashion. The only
difference between using an `-l' option and specifying a file name is that `-l' surrounds library with `lib' and `.a'
and searches several directories.
The -l option tells GCC to link in the specified library. In this case, the library is apue, and that it happens to line up with the name of a header file is just how the apue coders designed their project.
In reality, the -l option has nothing to do with header files. Like cas says in the comments, read the man page; it'll give you much more information.

Makefile -L command

If I have this line in the make file:\
libpqxx_Libs = -L/share/home/cb -lpqxx-2.6.9 -lpq
Does this indicate the compiler to use the lpqxx-2.6.9.so shared object file or does this indciate the compiler to use all the .so in the foler lpqxx-2.6.9? Or is this something else altogether?
Thanks for the help!
-L in this context is an argument to the linker, that adds the specified directory to the list of directories that the linker will search for necessary libraries, e.g. libraries that you've specified using -l.
It isn't a makefile command, even though it's usually seen in makefiles for C projects.
The -L is actually not a makefile command (as you state it in the title of your question).
What actually happens in this line is an assignment of a value to the variable libpqxx_Libs -- nothing more and nothing less. You will have to search in your makefile where that variable is used via $(libpqxx_Libs) or ${libpqxx_Libs}. That is most likely as a argument in a link command, or a compile command that includes linking.
In that context, the meaning of -L and -l can be found in, for example, the gcc man pages, which state that
-llibrary
Use the library named library when linking.
The linker searches a standard list of directories for the li-
brary, which is actually a file named `liblibrary.a'. The linker
then uses this file as if it had been specified precisely by
name.
The directories searched include several standard system direc-
tories plus any that you specify with `-L'.

Make gcc put relative filenames in debug information

The project I'm compiling uses CMake, which loves absolute pathnames.
When I compile with debugging information enabled, gcc puts those long names into .debug_str sections, which is bad for debugging. I'd like to have short relative-to-project-root pathnames there instead.
Is there some option to tell gcc to strip some part of pathname before emitting debug data? Or, maybe, there is some tool that could do that on compiled binaries?
I've tried using SET(CMAKE_USE_RELATIVE_PATHS ON) (which seems to be frowned upon by devs) option, but as I'm using out-of-source builds, pathnames are still not in the form I'd want them to be. I.e. they're ./../src/mod_foo/foo.c instead of mod_foo/foo.c.
You can use the -fdebug-prefix-map flag to remap the debugging information paths. For example, to make the paths relative to the build location use: -fdebug-prefix-map=/full/build/path=.
You can set the RULE_LAUNCH_COMPILE property of a CMake target to have CMake invoke a shell script which transforms the source file path to a project relative path before invoking gcc. Use the CMake function configure_file to generate a shell script which knows about the PROJECT_SOURCE_DIR and PROJECT_BINARY_DIR of your project.
In your outermost CMakeLists.txt add the following code:
configure_file(
"${PROJECT_SOURCE_DIR}/gcc_debug_fix.sh.in"
"${PROJECT_BINARY_DIR}/gcc_debug_fix.sh"
#ONLY)
add_executable (MyExecutable ...)
set_target_properties(MyExecutable PROPERTIES
RULE_LAUNCH_COMPILE "${PROJECT_BINARY_DIR}/gcc_debug_fix.sh")
The following template shell script gcc_debug_fix.sh.in needs to go to the root directory of the CMake project:
#!/bin/sh
PROJECT_BINARY_DIR="#PROJECT_BINARY_DIR#"
PROJECT_SOURCE_DIR="#PROJECT_SOURCE_DIR#"
# shell script invoked with the following arguments
# $(CXX) $(CXX_DEFINES) $(CXX_FLAGS) -o OBJECT_FILE -c SOURCE_FILE
# extract parameters
SOURCE_FILE="${#: -1:1}"
OBJECT_FILE="${#: -3:1}"
COMPILER_AND_FLAGS=${#:1:$#-4}
# make source file path relative to project source dir
SOURCE_FILE_RELATIVE="${SOURCE_FILE:${#PROJECT_SOURCE_DIR} + 1}"
# make object file path absolute
OBJECT_FILE_ABSOLUTE="$PROJECT_BINARY_DIR/$OBJECT_FILE"
cd "$PROJECT_SOURCE_DIR"
# invoke compiler
exec $COMPILER_AND_FLAGS -c "${SOURCE_FILE_RELATIVE}" -o "${OBJECT_FILE_ABSOLUTE}"
The shell script uses the information from the variables PROJECT_BINARY_DIR and PROJECT_SOURCE_DIR to transform the path of the source file to a path relative to the project root and the object file's path to an absolute path. Because gcc gets passed a project relative path now, .debug_str should use that path, too.
The following caveats apply:
Be sure to set the executable bit of gcc_debug_fix.sh.in.
For the script to work CMAKE_USE_RELATIVE_PATHS has to set to OFF again.
The script makes assumptions about the location of the file paths on the command line. This may not work if CMake uses a different rule to invoke the compiler. A more robust solution would be to scan the script arguments for the -o and -c flags.
If I really couldn't fix the make file/tool to do this properly, I would write a wrapper script for gcc that recognises absolute pathnames and converts then to relative ones.
It might look something like this in bash:
#!/bin/bash
out=()
for arg; do
out=("${out[#]}" $(echo "$arg" | sed 's:/my/absolute/directory/:../:'))
done
exec gcc "${out[#]}"
If your source directory has subdirectories then you'll need to handle those carefully, but the above should work for a flat source directory. I've not tested it though, and I wouldn't be surprised if I've got the quoting wrong, but that'll only be a problem if you have pathnames with spaces in. It also doesn't handle parameters like -I/whatever/include, but you can fix that.

Resources