Thursday, August 26, 2010
Speeding up your cabal builds
Author:
Every waited too long for your cabal builds to finish? If that’s because you have multiple executable sections in your .cabal file, then there might be a solution.
By default, cabal rebuilds all relevant object files for each executable in separation. In other words, object files are not shared between executables. So if you have n executables and m source files, then cabal needs n * m compilation steps plus n link steps to rebuild the executables, no matter whethe any source file contributes to multiple executables.
Starting with cabal 1.8, there is a better solution, provided your executables have some source files in common. In this case, you might build a library from these common source files and then link the executables against the library. In the example above, if all n executables use the same set of m source files, then you end up with m compilation steps plus n + 1 link steps. Sounds good, doesn’t it?!
Here is a simple .cabal file that demonstrates how linking against an internal library works:
Name: test Version: 0.1 Synopsis: test package for linking against internal libraries Author: Stefan Wehr Build-type: Simple Cabal-version: >=1.8 -- IMPORTANT Library Hs-source-dirs: lib -- IMPORTANT Exposed-modules: A Build-Depends: base >= 4 Executable test-exe Build-depends: base >= 4, test, -- link against the internal library Main-is: Main.hs -- imports A Hs-source-dirs: prog -- IMPORTANT
There are some things to consider:
- The Cabal-Version must be greater or equal 1.8.
- The library and the executable must not use common source directories, otherwise the compiler does not pick the library but recompiles the source files.
- The library must be mentioned in the Build-depends of the executable
Running cabal build now gives the following output:
Building test-0.1... [1 of 1] Compiling A ( lib/A.hs, dist/build/A.o ) Registering test-0.1... [1 of 1] Compiling Main ( prog/Main.hs, dist/build/test-exe/test-exe-tmp/Main.o ) Linking dist/build/test-exe/test-exe ...
No rebuilding of A when compiling Main!!!
This feature of cabal isn’t mentioned in the manual, at least I didn’t find it. Further, there seems to be no changelog for cabal. I found out about this feature by browsing the bug tracker for cabal. Is there a better way to get informed of new features of cabal?
Note: I successfully tested this with cabal-install version 0.8.2 (cabal library 1.8.0.4). I couldn’t get it to work with cabal-install version 0.8.0.
Author: Stefan Wehr
Tuesday, August 3, 2010
Cross-Compiling DLLs with Linux
Author:
Creating the DLL
Simply create a file example_dll.c with the fitting header example_dll.h#include "example_dll.h"
int example_function(int n) {
return n*42;
}
#ifndef EXAMPLE_DLL_H__
#define EXAMPLE_DLL_H__
int example_function(int n);
#endif
Then just compile it with:
$> i586-mingw32msvc-gcc -shared example_dll.c -o example.dll
and viola, you have your DLL ready to use. This is just a simple example DLL, but with this method it is possible to create full-blown DLLs with thousands of lines of code. When you keep your code clean and platform-independet you can compile the same code into a shared library for Linux and a DLL for Windows and even link against other dynamic libraries like OpenSSL or libcurl, though it is advisable to use GNU Automake and GNU Libtool when creating larger projects to ease the hassle of the growing command lines, especially because of different options for Windows and Linux. GNU Automake will take care of all that automatically, also when cross-compiling.
Using the DLL
Using the DLL is just as you would expect it. In this example just create a file use_dll.c with following content:#include <stdio.h>
#include "example_dll.h"
int main() {
int res = example_function(13);
printf("%d should be %d!\n", res, 13*42);
return 0;
}
Then your program compiles as simple as this, ready to use on any Windows system:
$> i586-mingw32msvc-gcc use_dll.c example.dll -o example.exe
Using GNU Automake
Creating DLLs with GNU Automake and GNU Libtool isn't difficult either. With your working Automake setup, simply add the macroAC_LIBTOOL_WIN32_DLL
to your configure.ac and GNU Libtool will create clean DLLs for your project when configured for cross-compiling.
Using the DLL with MSVC
To link the DLL against a project in MSVC you will have to generate a .lib file, and for that you will have to generate a .def file. So when compiling on your Linux machine just add the following parameter to your gcc comandline:-Wl,--output-def,example.def
which will tell the linker to output the .def file as example.def. Then on your Windows machine with a installation of some kind of MSVC compiler execute following command:
lib /machine:i386 /def:example.def
to compile the .def into a .lib which you can then link against in your project. Don't forget to do this step every time your API changes...
Author: Jonathan Dimond