Showing posts with label GNU Autotools. Show all posts
Showing posts with label GNU Autotools. Show all posts

Tuesday, January 19, 2016

Using Boost C++ Library from C

This post is related to another post: Building C++ Application with Boost Library and Autotools in Linux. If you haven't know how to use Boost C++library in an autotools project, please read that post.

The purpose of this post is to explain what you need to do to use use Boost from your C language code. The following are the steps required to use Boost from C:
  1. Decide which part of Boost that you require in your C application.
  2. Wrap that part of Boost as "convenience" C library.
  3. Link your C application code to the "convenience" library. 
The steps above is easier said than done. Don't worry, I have provided a sample project over at github: https://github.com/pinczakko/boost_spsc_queue_c_wrapper. Just download the code and try to make sense of it.
DISCLAIMER
-----------
- The code assumes that the platform in which it runs has a working pthread implementation.
- The code is not production quality code. Use it at your own risk.
The sample code basically wraps Boost SPSC (single producer single consumer) lockfree queue into a convenience C library and the sample application links to the convenience library.

Anyway, the most important part of the code that you need to understand is the part that "returns" a C++ class as an "opaque" C structure. Probably, it's a quite alien concept. But, I assure you that this alien concept is the core of C<-->C++ interoperability. Below is the relevant code snippets:


//---- START spsc_interface.hpp file -----------------
#ifndef  SPSC_WRAPPER_H
#include "spsc_wrapper.h"
#endif //SPSC_WRAPPER_H 

class spsc_interface {
public:
    explicit spsc_interface();
    explicit spsc_interface(const spsc_interface &);
    ~spsc_interface() {};
//...

};
//---- END spsc_interface.hpp file -----------------

//---- START spsc_wrapper.h file -----------------
#ifdef __cplusplus
extern "C" {
#endif
//...
 typedef struct spsc_interface spsc_interface;

 spsc_interface *create_spsc_interface();

//---- END spsc_wrapper.h file -----------------

//---- START spsc_wrapper.cc file -----------------

#include "spsc_interface.hpp"
#include "spsc_wrapper.h"

#ifdef __cplusplus
extern "C" {
#endif

spsc_interface * create_spsc_interface()
{
    return new spsc_interface();
}

...
#ifdef __cplusplus
}
#endif
//---- END spsc_wrapper.cc file -----------------

As you see above, the wrapper function create_spsc_interface() returns an opaque object of type struct spsc_interface. In fact, this opaque object is a C++ class in disguise as you can see in the spsc_wrapper.cc snippet above. If you ask: How's that possible? Well, the answer lies in the linking process. Let's see the relevant snippets from src/Makefile.am:

wrapper_test_SOURCES = wrapper_test.c 
### Below is just a trick to force using C++ linker
nodist_EXTRA_wrapper_test_SOURCES = dummy.cc 

As you can see, we're not using a C linker to link the entire project, but we use a C++ linker (by tricking autotools ;) . A C++ linker "understand" the idiom used in spsc_wrapper.cc above.

Wednesday, December 30, 2015

Building 64-bit AIX Executables with Autotools


Creating 64-bit AIX executable is not quite as straight forward as in other platforms if you are using Autotools' Libtool. Actually, even if you don't use Autotools' Libtool, it would still be not really as straightforward as in other platform supported by GNU Autotools. I'm not going to present an example code that runs on AIX as 64-bit executable in this post. However, I'll show you how to build such program with the correct build script, with the assumption that you are using GNU Autotools.
Now, you've got the basics. Let's proceed to the real stuff. Below is the abridged version of the build script I use to build the debug version of my autotools project in AIX:
#!/bin/sh

## NOTE:
## -----
## - Passing native linker flag via LDFLAGS worked as documented in libtool (as shown below). 
##
## - For more info on native AIX ar archiver, see: 
##   https://www-01.ibm.com/support/knowledgecenter/ssw_aix_53/com.ibm.aix.cmds/doc/aixcmds1/ar.htm?lang=en 
##
## - For more info on native AIX linker, see: 
##   https://www-01.ibm.com/support/knowledgecenter/ssw_aix_53/com.ibm.aix.cmds/doc/aixcmds3/ld.htm?lang=en 
##

case "$1" in 

      AIX) ./configure CFLAGS="-DDEBUG -fstrict-aliasing -Wstrict-aliasing=2 -g -O0 -maix64" \
    LDFLAGS="-Wl,-b64" AR='ar -X32_64' && make V=1
    ;;
      ###... 
esac

Mind you that I'm using libtool in the autotools project that uses the build script above. As you see, you need to pass the correct flags to the compiler (I'm using GCC on AIX), the linker and tools invoked by libtool (if you're using libtool). The -Wl flag is a libtool flag used for passing flags directly to the underlying linker. In this particular case, the linker is AIX native linker (see: AIX ld Command). The next thing to pay attention to is the ar archiver is AIX native archiver. This archiver only supports 32-bit object file by default. Therefore, you must explicitly override ar setting to force it to switch to support 64-bit object code, as shown above. See AIX ar command for more details on the archiver.

The release version of the build script is not that different from the debug version. I think you could figure it out already.

Hopefully this helps those working with Autotools projects in AIX.

Friday, December 25, 2015

The Importance of Reading Autoconf and Automake Manuals

The title of this post is possibly an understatement. However, time and again, silly questions and "stupid"/inappropriate way of using software tools can be prevented. This is especially applies to all GNU-related tools. If you've installed GNU tools such as Autotools, you must read its accompanying manual, preferably via:
$ info autoconf
$ info automake
Take your time to learn how to use keyboard navigation by pressing "?" key to enter the navigation help menu.

You'll appreciate the manuals better after seeing questions like this at Stackoverflow. Let me copy the relevant question here:
I've been looking for this for a while: I'm currently converting a medium-size program to autotools, coming from an eclipse-based method (with makefiles)
I'm always used to having a "debug" build, with all debug symbols and no optimizations, and a "release" build, without debug symbols and best optimizations.
Now I'm trying to replicate this in some way with autotools, so I can (perhaps) do something like:
./configure
make debug
Which would have all debug symbols and no optimizations, and where:
./configure
make
Would result in the "release" version (default)
PS: I've read about the --enable-debug flag/feature, ...
Well, this question is kind of "stupid" if you have read Automake manual. The manual explains the answer to such question in detail in section 2.2.6 Parallel Build Trees (a.k.a VPATH Builds), thorough an example. The title of section 2 of the manual is An Introduction to the Autotools. I think now you know where I'm getting at without going further.  I have to give kudos to William Purcell for his answers in that Stackoverflow thread.

Now, the unfortunate fact that many developers failed to see the value of reading the manual. The prove is everywhere, if you found a package that uses Autotools and provide a "./configure --enable-debug" flag which changes the compiler flags such as the optimization flag, then it's a sign of trouble because the "maintainer" of the code certainly doesn't follow GNU autotools philosophy in creating his package and make other people life harder. FYI, in GNU software terminology, the maintainer is one who create the software package, while user is one who compile and install the package.

Well, that's it for reminder to RTFM.

Saturday, November 21, 2015

Autotools Conditional Makefile Creation via AM_COND_IF

There are times when you need to generate several Makefiles in one platform but want to prevent generating the same Makefile in another platform, or to generate different Makefile for the latter platform. This is where AM_COND_IF (http://www.gnu.org/s/automake/manual/html_node/Usage-of-Conditionals.html) comes to the rescue.

As cool AM_COND_IF sounds, it takes a bit of exercise to make it work as you intend due to lack of documentation. At least for those not savvy enough with m4 macro language. Now, let's get down to business. These are the rules:
  • AM_COND_IF cannot be invoked twice with the same Makefile output (assuming you're using AC_CONFIG_FILES with AM_COND_IF).
  • You need to create automake conditionals first before using AM_COND_IF
Now, let's look at a sample configure.ac that uses AM_COND_IF.
# Platform specific checks
libevent_test_on_linux="no"

# For host type checks
AC_CANONICAL_HOST
# OS-specific tests
case "${host_os}" in
    *linux*) 
    # Define we are on Linux
    AC_DEFINE(HAVE_LINUX, 1, [Current OS is Linux]) 
       libevent_test_on_linux="yes"
    ;;
esac

AM_CONDITIONAL(ON_LINUX, test "x$libevent_test_on_linux" = "xyes")   

# Generate Makefile based on current OS
AC_CONFIG_FILES([Makefile
                 lib1/Makefile
                 lib2/Makefile
                 experiment_2/Makefile])

AM_COND_IF([ON_LINUX], 
           [AC_CONFIG_FILES([linux_specific_lib/Makefile])])

As you can see, the first invocation of AC_CONFIG_FILES instructs automake to generate Makefile for used by all build platforms. The second invocation of AC_CONFIG_FILES (inside AM_COND_IF), only generate Makefile if the target operating system is Linux. If, for example, you want to support other operating system via a different set of OS-specific Makefiles, you can just copy the Linux implementation and add it to configure.ac, modify the Linux implementation to suit your need.

That's it. Hopefully, this helps those playing around with using AM_COND_IF. The key takeaway is: never ever call AC_CONFIG_FILES with the same target Makefile output twice! Even from inside AM_COND_IF. Autotools will complain if you do so and you won't be able to generate the Makefile via autoreconf. You must invent a way to make AC_CONFIG_FILES conform to this rule.

Thursday, November 5, 2015

Supporting Out-Of-Source-Code-Tree Build with Autotools

Some opensource code are not trivial to be build out of it's source (code) tree. This is especially true in some opensource libraries because they generate intermediate file(s) which must be handled accordingly. But, fear not, there are two Autoconf constructs (or rather internal variables) that can help you tame this wild library code. They are $(top_srcdir) and $(top_builddir). Refer to Autoconf Preset Output Variables for their details.

I'll take libevent as a real-world example because this library generates an intermediate header file at build time which must be included in the build process (event-config.h). This is where $(top_srcdir) and $(top_builddir) come into play. If you want to be able to build out-of-source-tree, you need to include this generated file into your application code that uses libevent. You use $(top_builddir) for that. In the meantime, you also need to include the "ordinary" include file in the source tree, and that's where $(top_srcdir) comes into play.

Let's assume, your source tree looks like below and your application links to this particular libevent version statically:
.
├── libevent-2.0.22-stable
│   ├── autom4te.cache
│   ├── compat
│   │   └── sys
│   ├── include
│   │   └── event2
│   ├── m4
│   ├── sample
│   ├── test
│   └── WIN32-Code
│       └── event2
└── your_application_code_dir

In your_application_code_dir, you need to have a Makefile.am file with the following contents:
### NOTE:
### $(top_builddir) is required for libevent because there is 
### an include file (event-config.h) that is generated at build-time.
### This file will be in the build directory instead of the source code 
### directory if you build out-of-tree.
###
AM_CPPFLAGS = -I$(top_srcdir)/libevent-2.0.22-stable/include \
       -I$(top_builddir)/libevent-2.0.22-stable/include
  

## Omitted for clarity .. 

bin_PROGRAMS = your_program_name

your_program_name_SOURCES = your_program_name.c
your_program_name_LDADD = $(top_builddir)/libevent-2.0.22-stable/libevent_core.la

## Omitted for clarity .. 
The code in Makefile.am above (placed in your_application_code_dir) should be enough to make it possible to build libevent out-of-source-tree. As you see, both the include file in the build directory (out of the source code tree) and the include file in the source code tree are included. This should make it less of hassle to keep your source code tree clean all the time. Especially if you are using RCS such as subversion, git or mercurial.

Hopefully this helps those who intend to always build autotools code out-of-(source)-tree.

Wednesday, October 14, 2015

Building C++ Application with Boost Library and Autotools in Linux

In this post, I'm going to present the steps required to build C++ application which uses Boost library in Linux (x86_64) with the help of GNU autotools. Mind you that I'm using Arch Linux distribution. Therefore, please adjust the prerequisites according to your environment.

Prerequisites

  • The usual GCC tools, i.e. g++ compiler, ld linker, etc.
  • GNU autotools: autoconf, automake, etc.
  • autoconf-archive. This is a set of autoconf macros that will help building Boost applications. In Arch Linux, I used pacman to install it. You need to carry-out similar step in your Unix/Linux installation.

Initializing The Build System

I assume that the source code directory entries look like this:
.
├── configure.ac
├── m4
├── Makefile.am
└── src
    ├── main.cpp
    └── Makefile.am

m4 is an empty directory, configure.ac, Makefile.am, and src/Makefile.am are the boiler-plate code required to initialize the autotools build system. The next section shows you contents of the files. Use autoscan and autoreconf to initialize the autotools build system like so:
  1. Run autoscan (in the root source code directory) to create configure.scan template file. You need to copy/rename this file to configure.ac and edit it accordingly.
  2. Run autoreconf to create files required by GNU build tools (GNU make and gcc/g++). The following is how you would run autoreconf to create the files.
    $ autoreconf -fvi
    

Dealing with Boost Modules

Every boost module requires separate dependency library, autoconf macro (in configure.ac) and automake "library entry" (in Makefile.am). Now let's start with configure.ac. Contents of <ROOT_DIR>/configure.ac is as follows:
# configure.ac
#                                               -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.

AC_PREREQ([2.69])
AC_INIT([boost_test], [0.0.1], [me@bug.com])
AC_CONFIG_SRCDIR([config.h.in])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_MACRO_DIR([m4])

AM_INIT_AUTOMAKE([foreign -Wall -Werror])
m4_ifdef([AM_SILENT_RULES],
    [AM_SILENT_RULES([yes])
])

# Checks for programs.
AC_PROG_CC
AC_PROG_CXX

# Checks for libraries.
AX_BOOST_BASE([1.48],, [AC_MSG_ERROR([This program needs Boost, but it was not found in your system])])
AX_BOOST_SYSTEM
AX_BOOST_DATE_TIME
AX_BOOST_THREAD

# Checks for header files.

# Checks for typedefs, structures, and compiler characteristics.

# Checks for library functions.

AC_CONFIG_FILES([Makefile
                 src/Makefile])
AC_OUTPUT

TODO: Explain the lines that have something to do with Boost (AX_BOOST_*) in configure.ac 

Contents of <ROOT_DIR>/Makefile.am is as follows:
ACLOCAL_AMFLAGS = -I m4
EXTRA_DIST = bootstrap
SUBDIRS = src
<ROOT_DIR>/src/Makefile.am is as follows:
bin_PROGRAMS = boost_test

AM_CPPFLAGS = $(BOOST_CPPFLAGS)
AM_LDFLAGS = $(BOOST_LDFLAGS)

boost_test_SOURCES = main.cpp
boost_test_LDADD = $(BOOST_SYSTEM_LIB) $(BOOST_THREAD_LIB) $(BOOST_DATE_TIME_LIB) 

TODO: Explain the lines that have something to do with Boost in src/Makefile.am -- $(BOOST_CPPFLAGS) $(BOOST_LDFLAGS) $(BOOST_*_LIB)

Contents of <ROOT_DIR>/src/main.cpp is as follows:
#include <iostream>
#include <boost/thread.hpp>
#include <boost/date_time.hpp>

void workerFunc()
{
 boost::posix_time::seconds workTime(3);

 std::cout << "Worker: running" << std::endl;

 // Pretend to do something useful...
 boost::this_thread::sleep(workTime);

 std::cout << "Worker: finished" << std::endl;
}

int main(int argc, char *argv[])
{
 std::cout << "main: startup" << std::endl;

 boost::thread workerThread(workerFunc);

 std::cout << "main: waiting for thread" << std::endl;

 workerThread.join();

 std::cout << "main: done" << std::endl;

 return 0;
}

Pay attention that each Boost module is represented by a single header file which also requires autoconf entry in configure.ac and corresponding library dependency in src/Makefile.am

END NOTE: This post is still incomplete. It's published solely for the benefit of those who can understand it quite well from the source code itself.

Friday, September 11, 2015

Makefile.am "option subdir-objects is disabled" Warning and Fix

The "option subdir-objects is disabled" warning is thrown-up by GNU autotools when Makefile.am builds a source file in a subdirectory located beneath the Makefile.am's file. This is an example warning:
.. Makefile.am:4: warning: source file '$(srcdir)/test.c' is in a subdirectory,
.. Makefile.am:4: but option 'subdir-objects' is disabled
This warning is not fatal. What it means roughly: the generated object file will not be placed inside the same directory as the source code. The full explanation is at https://www.gnu.org/software/automake/manual/html_node/List-of-Automake-options.html#List-of-Automake-options (scroll-down to subdir-objects option). This is the important excerpt:
subdir-objects

If this option is specified, then objects are placed into the subdirectory of the build directory corresponding to the subdirectory of the source file. For instance, if the source file is subdir/file.cxx, then the output file would besubdir/file.o.
Fixing this problem is not hard, you just need to add the subdir-objects option to Makefile.am. Below is an example taken from Makefile.am in one of my project. I placed the statement as the first entry in Makefile.am.
AUTOMAKE_OPTIONS = subdir-objects
### ...
### Other statements
### ...
Hopefully, this helps out those experiencing this problem.

Sunday, July 12, 2015

Cross-Compiling Raspberry Pi Application from Windows with CodeBlocks

Let's start with problem definition: Raspberry Pi is too slow for most complex software compilation/build process. Therefore, we need something much more powerful. "Unfortunately" for me, I'm left with a Windows 8.1 Professional machine due to my day job with Micro$oft stuff as that something much more powerful. But, never mind, there's a solution for that platform problem. My machine is quite powerful, a Core i5 4200U (2.xx GHz @turboboost) with an 8GB RAM.

Anyway, there's a quite mature GNU Toolchain for this cross compilation task, kindly provided by Sysprogs: http://gnutoolchains.com/raspberry/. It even comes with the tutorial to use it: http://gnutoolchains.com/raspberry/tutorial/. However, it doesn't explain how to use the cross toolchain in CodeBlocks because it expect you to use Visual Studio. Well, Visual Studio is just way too resource hungry for my taste. Therefore, let's find out how to use the cross toolchain with CodeBlocks.

Footnote:
-------------
- This post is incomplete. However, I decided to post it as it could help as starting point for those really looking into doing this kind of thing. I've left Windows for about a year now. Therefore, this has no relevance to me as of now.