Building only a small subset of project using autotools - makefile

I have a large project using autotools that contains some code that builds into a utility library. The project has quite a few dependencies and I would like to compile a specific subset of that utility library for mobile environments (Android/iOS). I expect a lot of dependencies to be unnecessary for that particular subset of functionality, and compiling the whole project for those architectures/platforms is impossible for technical reasons.
This mini version of the library would actually be useful not just to me but other people, as well. This is why the maintainer of the project suggested introducing a --enable-mini flag for the configure script. After experimenting a little (I have never done anything inside a configure.ac before) I actually got a build working that builds this extra mini library.
Now to the point: Is there a clean way to exclude all the other project executables and libraries from being built? What I want is a ./configure --enable-mini invocation that will result in only the libutilmini.a/libutilmini.la being built. Sure, there are some components that could be disabled via --disable-X options, but obviously the project was not set up in a way that makes all components optional. Apart from the fact that it does not seem necessary to build everything else just to build the mini library, the whole project will not build for, for instance, the iOS platform.
I really would like to avoid adding an if HAVE_MINI [...] to all the Makefile.ams in every subdirectory, especially since the mini library is not useful to most of the other developers, this does not seem like an elegant approach. Are there any recommended ways of achieving these goals?
I am aware I could just create a new project using the sources I need and build those, but as I said the mini library is useful to some other developers, too.

If you want to conditionally compile something with automake using a regular make command with no arguments, you have to use automake conditionals (the if HAVE_MINI thing you refer to); there is no other way. However, what you can do, alternatively, is to create an extra target (say, build_mini) in your toplevel Makefile.am which depends on everything needed to build your libmini. You could then tell people that if they want to build libmini (and nothing else), they don't run make, but they run make build_mini. This would look something like:
(toplevel Makefile.am)
SUBDIRS = foo bar baz
build_mini:
$(MAKE) -C foo libmini-depends
$(MAKE) -C bar libmini.la
or some such (the details would depend on what is needed to build libmini.la).
You would then have bar/Makefile.am look something like this:
if WANT_MINI
lib_LTLIBRARIES += libmini.la
endif
libmini_la_SOURCES = # ...
the only thing that really needs to be inside the conditional is adding the libmini.la to lib_LTLIBRARIES; everything else can be unconditional. So with this method, you should have only one if FOO...endif construct.

Related

Methods for Targeting Multiple Embedded Hardware Platforms with GNU Make

How can I ensure that object files compiled for one hardware target will not be used for a different hardware target that needs to be compiled differently?
I am using the GNU ARM Embedded Toolchain while I am learning about embedded development. I already have a couple of development boards (with STM32F0 and STM32F4 processors), and plan to make my own boards in the future. I want to have several iterations of hardware using a common software repository.
Obviously I will have multiple targets in my Makefile, invoking the appropriate defines and compiler flags for each platform, and perhaps a make all to build for all platforms at once. As I understand it, make is an incremental build system that only re-compiles object code (*.o) files if the source file has been changed, it won't recompile if I have use different defines and options, and the wrong object code will be passed to the linker.
It seems that I could diligently make clean when switching between different targets, but that would rely on the human action and could produce bad builds if I forgot, and could not be used for a make all that produces multiple binaries for their respective hardware.
Edit Notes: Per feedback comments, I have shorted and rearranged to make the question more clear and objective. I'm not asking generically how to use Make, but rather how to prevent, say mylib.o being compiled for an STM32F0 and then later being re-used in a build for an STM32F4.
I am curious about alternative tools, and welcome discussion in the comments, but this question is specific to GNU Make.
To avoid the need for a clean build between targets, it is necessary for each target to have separate build directories in order that the target dependencies are independent and specifically generated using the appropriate tool chain and build switches etc.

How to use CMake to build multiple platforms from one master CMake project without cache problems

I have two projects called A and B that have complete working CMakeLists.txt projects, and each project can be built completely without errors. I would like to have a master project defined in CMake that will build both A and B (and maybe a hundred other things eventually).
My top level CMakeLists.txt project looks like
add_subdirectory(A build-A)
add_subdirectory(B build-B)
and CMake can parse all the files and make can start building just fine.
The problem is that project A is for one architecture (x86_64) and B is for a different architecture (k1om) and when CMake invokes various features like
find_package(Boost ....)
it caches the results of the library paths for the first architecture and reuses them (incorrectly!) for all subsequent architectures. We have Boost compiled for both x86_64 and k1om.
Is there a way to have CMake do what I want to do, by entirely invalidating the cache between the two projects? Something like this would be ok:
add_subdirectory(A build-A)
cmake_invalidate_cache_and_forget_everthing_that_just_happened()
add_subdirectory(B build-B)
cmake_invalidate_cache_and_forget_everthing_that_just_happened()
...
I am fully aware that I can just make a shell script that does this and just runs cmake multiple times in different output directories, but it would be really nice to have a uniform "entry" point for all projects written in CMake.
I'd recommend using a "super-build" setup whereby each subproject is included via ExternalProject_Add rather than add_subdirectory. This gives very clean separation between the subprojects' builds. I think you'd be fighting CMake very hard by trying to tinker with the generated CMakeCache.txt!
However, I've never tried actually doing this where the architecture differs between subprojects. So all I can do is suggest you try it - I think it should work.
(This article may help).
I think using ExternalProject, as Fraser suggests is the best practice for your setup, but I don't think it's going to solve the issue your having. Correct me if I'm wrong, but it sounds like you're using the same build tree for both platforms. Is that correct? If so, I can't see what can be gained from that.
If I'm wrong and you're just trying to prevent certain projects from configuring on certain architectures, then you should look into CMake's architecture blocks, like if(WIN32) ... if (CMAKE_SIZEOF_VOID_P 8) ... there are many other ways to limit code exposure base on compiler, 32 vs 64 Windows, *nix, MAC, etc ...
If I'm still not understanding, then my apologies, perhaps you can attempt a clear explanation. Perhaps all you need it the unset command for your cache variables that are incorrectly set in cache because of a different architecture. See: http://www.cmake.org/cmake/help/v3.0/command/unset.html
If that's the case though, you really should reconsider the design of your project because that approach sounds like an unmaintainable mess. Sorry.
I got it to work with ExternalProject_Add (Thank You Fraser). Here is what it looks like:
cmake_minimum_required(VERSION 2.8.4)
project(Demo1)
include(ExternalProject)
ExternalProject_Add(
A-build
SOURCE_DIR ${CMAKE_SOURCE_DIR}/A
INSTALL_COMMAND ""
)
ExternalProject_Add(
B-build
SOURCE_DIR ${CMAKE_SOURCE_DIR}/B
INSTALL_COMMAND ""
)

How do I tell ld to ignore a missing library?

I'd like to define a Makefile with implicit rules for a bunch of executables, some of which require linking against a custom-built library (let's call it libedich.a).
My problem is that I'd like to be able to build those executables that do not require libedich.a when the latter hasn't been built yet. If I simply add -ledich to the LDLIBS variable, I get errors when libedich.a doesn't exist:
/usr/bin/ld: cannot find -ledich
How do I tell ld that it's okay to continue linking when a given library doesn't exist?
A common solution is to create a dummy archive so that GCC will find it. Since the executable doesn't need any symbols from the library, it won't error out. Like this,
# create an empty archive.
ar cru libedich.a
or even simpler,
echo '!<arch>' >libedich.a
This is the downside of using one LDLIBS variable to hold all of the library dependencies and re-using it for every target, even though you know some targets only need a subset of the libraries. You have several options:
There are probably fancy IDE's and build tools out there that try to infer library dependencies from context, saving you from manually specifying them for each target.
Switch to using shared libraries.
Fix the target in your Makefile so that it depends on libedich.a (even if it doesn't need to). This will work if you are building everything anyway and don't care what order the targets proceed in.
Manually specify the library dependencies for each target in your Makefile.
The last option is my recommendation; it is more work, but eliminating the false dependencies in your Makefile will enable you to build (perhaps most of) your targets even if one of the dependencies is broken. One convenient way to do this is with target-specific variables:
targetname::LDLIBS+=-ledich
You probably also want to be aware of make --keep-going (make -k)

How to affect order of targets, add additional steps etc. for Makefile.am?

Can I manage Makefile.am as I got used to manage Makefile?
Usually I create targets which calls each other in order to make the project built.
But in Makefile.am I have some mysterious libqqq_la_SOURCES = ... which I don't know what is it doing exactly.
Where to write what compiler should it use for the given source? Where to add a step that "qqq.c is generated from qqq.vala"?
How to write Makefile.am as just Makefile?
Automake in 1.11 does have Vala support.
configure.ac:
AM_PROG_VALAC
Makefile.am:
AM_VALAFLAGS = whateverelse
whatever_SOURCES = xxx.vala
Automake will automatically copy over any Make targets you specify in Makefile.am into the generated Makefile. So you can generate any custom, complicated things just by including it in the .am file.
However, you shouldn't do this for everything -- that defeats the benefit that Automake is trying to provide you. Specifying
bin_PROGRAMS=foo
AM_CFLAGS=$(DEPS_CFLAGS)
foo_SOURCES=file1.cpp file2.cpp
foo_LDADD=$(DEPS_LIBS)
will generate a standard Make target anyway. I recommend you learn to use Automake macros for most standard things -- it will be more portable that way.
The best way to learn the rich variety of Autotools features is not to read the manual -- it's way too complicated and unorganizable. My suggestion is simply to take an existing open-source GNU project that is similar in build style (dependencies, platforms, etc) to yours, and examine its Autoconf and Automake files. The established projects have learned quite a few tricks that you can learn from.

Perfect makefile

I'd like to use make to get a modular build in combination with continuous integration, automatic unit testing and multi-platform builds. Similar setups are common in Java and .NET, but I'm having a hard time putting this together for make and C/C++. How can it be achieved?
My requirements:
fast build; non-recursive make (Stack Overflow question What is your experience with non-recursive make?)
modular system (that is, minimal dependencies, makefile in subdirectory with components)
multiplatform (typically PC for unit testing, embedded target for system integration/release)
complete dependency checking
ability to perform (automatic) unit tests (Agile engineering)
hook into continuous integration system
easy to use
I've started with non-rec make. I still find it a great place to start.
Limitations so far:
no integration of unit tests
incompatibility of windows based ARM compilers with Cygwin paths
incompatibility of makefile with Windows \ paths
forward dependencies
My structure looks like:
project_root
/algorithm
/src
/algo1.c
/algo2.c
/unit_test
/algo1_test.c
/algo2_test.c
/out
algo1_test.exe
algo1_test.xml
algo2_test.exe
algo2_test.xml
headers.h
/embunit
/harnass
makefile
Rules.top
I'd like to keep things simple; here the unit tests (algo1_test.exe) depend on both the 'algorithm' component (ok) and the unit test framework (which may or may not be known at the time of building this). However, moving the build rules to the top make does not appeal to me as this would distribute local knowledge of components throughout the system.
As for the Cygwin paths: I'm working on making the build using relative paths. This resolves the /cygdrive/c issue (as compilers can generally handle / paths) without bringing in C: (which make dislikes). Any other ideas?
CMake together with the related tools CTest and CDash seem to answer your requirements. Worth giving it a look.
Bill Hoffman (A lead CMake developer) refers to the Recursive Make Considered Harmful paper in a post at the CMake mailing list:
... since cmake is creating the makefiles for you, many of the disadvantages
of recursive make are avoided, for example you should not have to debug
the makefiles or even think about how they work. There are other examples
of things in that paper that cmake fixes for you as well.
See also this answer for "Recursive Make - friend or foe?" here on stackoverflow.
-
Recursive Make - friend or foe?
Ok here is what I do:
I use one Makefile at the root and wildcard patterns to collect all files in a directory. Note that I assume that foo/*.c will make up foo.so for example. This makes the maintaining the Makefile minimal, since just adding a file to the directory automatically adds it to the build.
Since it is make you are using I am assuming (I do that for my projects) that a compiler is used that uses gcc (cc) compatible command line syntax. So MSC is out of order; but don't get frustrated, I do most of my development (unfortunately) on Windows and use MinGW with MSys; works like a charm. Produces native binaries, but was built with a Posix compliant build environment.
Dependency checking is done with the somewhat standard -MD switch. I then include all the *.d files into the Makefile. I build the patterns out of the automatically collected source files.
Finally unit tests are implemented with the "standard" check target. The check target is like the all target, except it depends on the unit test and executes that once everything is built. I do it this way so that you can just build the project or build the unit tests (and the rest of the project) separably. When I am not developing the project I want to just build it and be done with it.
Here is an example of how I do it: https://github.com/rioki/c9y/blob/master/Makefile
It also has the install, uninstall and dist targets.
As you can see everything is plain make, no recursive make calls and all is relatively simple. I used automake and autoconf and I will never do that again; also other build tools are out of the question, if I need to install foojam or barmake to build something, I normally ditch that project immediately.

Resources