使用GNU Autotools为多个库使用相同的源文件

时间:2014-05-26 12:19:15

标签: autotools

我正在开发一个C / C ++项目,我使用GNU Autotools进行构建。我的目录结构如下:

..
adapter/
    libraryA/
        include/
        src/
        ..
    libraryB/
        include/
        src/
        ..            
    ..
src/
    Log.cpp
    ..

除了libraryAlibraryB之外,我还在顶层有一个库,称之为libraryMain,它们都使用来自Log.cpp的{​​{1}} src 。如果我使用传递给--disable-dependency-tracking的{​​{1}}选项构建了非源代码(另请参阅我的帖子here),configure会抱怨

  

libtool:link:`Log.lo'不是有效的libtool对象

关联libtool时,因为libraryMain在构建Log.losrc时生成了libraryA,然后由libraryB引用。如果我从libraryMain手动删除Log.lo并重建src,则一切正常,因为libraryMainlibraryMain中生成了自己的Log.lo

为了使事情更加清晰,我build/src Makefile.am(位于libraryMain)的内容如下所示:

src

.. libcomana_@COMANA_API_VERSION@_la_SOURCES = \ .. \ Log.cpp .. 的{​​{1}}(位于Makefile.am

libraryA

我已经明白问题是由于adapter/libraryA/src中的库没有将生成的.. libraryA_la_SOURCES = \ .. \ $(top_srcdir)/src/Log.cpp .. 文件放在他们自己的目录中,而是直接放在项目根目录下的adapter目录下。我实际上假设没有libtool对象放在源代码树中,而是放在构建树中,就像.lo一样。作为第一个解决方法,我在srclibraryMain中为src/Log.cpp创建了一个符号链接,但我认为这可能不是很优雅。我真的希望自己足够清楚。我非常感谢对此问题的任何评论。

1 个答案:

答案 0 :(得分:1)

好的,我认为我的问题可能有点不清楚。总结一下,我通过省略--disable-dependency-tracking选项并将我的Makefile.am更改为不包含前缀为$(srcdir)$(top_srcdir)的任何来源来规避问题,因为这似乎让人感到困惑automake,至少在构建非源代码时(另请参阅我的帖子herethis错误报告)。虽然我不知道这是否适合这个,我决定设置一个小例子,它可以正常工作并避免我在我的问题中描述的问题。

我的目录结构如下:

autogen.sh
configure.ac
Makefile.am
adapter
    Makefile.am
    adapterA
        Makefile.am
        include
            foo.h
        src
            foo.cpp
            Makefile.am                
    adapterB
        Makefile.am
        include
            foo.h
        src
            foo.cpp
            Makefile.am
debug
include
    hello.h
m4
src
    hello.cpp
    helloconf.sh.in
    Makefile.am

这些文件包含以下代码:

autogen.sh

#!/bin/sh

# GNU autotools toolchain
libtoolize --automake
aclocal
autoheader
automake --add-missing --force-missing --gnu
autoconf

configure.ac

dnl Process this file with autoconf to produce a configure script.

dnl Project name and version
AC_INIT([hello], [0.1])

dnl Library version information
AC_SUBST([HELLO_API_VERSION], [0.1])
AC_SUBST([HELLO_SO_VERSION], [0:0:0])

dnl Create a separate header with C preprocessor `#define` statements
AC_CONFIG_HEADERS([config.h])

dnl Look for auxiliary scripts in the current directory
AC_CONFIG_AUX_DIR([.])

dnl Automake initialization
dnl -Wall Show warnings
dnl -Wall Treat warnings as errors
dnl subdir-objects Place generated object files (.o) into the same as 
dnl                directory their source files, in order to avoid 
dnl                collisions when non-recursive make is used
AM_INIT_AUTOMAKE([-Wall subdir-objects])
m4_ifdef([AM_PROG_AR], [AM_PROG_AR])

dnl Libtool settings
LT_INIT([disable-static])
AC_CONFIG_MACRO_DIR([m4])

dnl Doxygen
dnl DX_HTML_FEATURE(ON)
dnl DX_PDF_FEATURE(OFF)
dnl DX_INIT_DOXYGEN([$PACKAGE_NAME], [Doxyfile], [doc])

dnl Checks for programs
AC_PROG_CXX([g++])
AC_PROG_INSTALL
AC_PROG_LN_S
AM_PROG_LIBTOOL

dnl Use the C++ compiler for the following checks
AC_LANG([C++])

dnl Checks for libraries

dnl Checks for header files
AC_HEADER_STDC
AC_CHECK_HEADER(iostream)

dnl Checks for typedefs, structures, and compiler characteristics
AC_TYPE_SIZE_T

dnl Checks for library functions

dnl Compiler and linker flags
AC_SUBST([AM_CXXFLAGS], [-Wall]) # C++
AC_SUBST([AM_LDFLAGS], [-Wall]) # ld (Linker)

dnl Libraries
AC_SUBST([LIBS])

AC_CONFIG_FILES(
    Makefile
    adapter/Makefile
    adapter/adapterA/Makefile
    adapter/adapterA/src/Makefile
    adapter/adapterB/Makefile
    adapter/adapterB/src/Makefile
    src/Makefile
    src/helloconf.sh
)

AC_OUTPUT

Makefile.am

# Process this file with automake to produce Makefile.in

# Independent executable script for inclusion in the distribution archive
dist_noinst_SCRIPTS = autogen.sh

# Look for additional autoconf macros in the m4 subdirectory
ACLOCAL_AMFLAGS = \
    -I m4 \
    @ACLOCAL_FLAGS@

# Subdirectories
SUBDIRS = \
    adapter \
    src 

# Entire directories copied recursively into the distribution
EXTRA_DIST = 

# Delete anything except for files required to run `./configure && make`
MAINTAINERCLEANFILES = 

# Delete anything which should not be part of the distribution
DISTCLEANFILES = 

adapter/Makefile.am

# Process this file with automake to produce Makefile.in

SUBDIRS = \
    adapterA \
    adapterB

adapter/adapterA/Makefile.am

# Process this file with automake to produce Makefile.in

SUBDIRS = src

adapter/adapterA/include/foo.h

#ifndef FOO_H_
#define FOO_H_

void foo();

#endif

adapter/adapterA/src/foo.cpp

#include <iostream>

#include "foo.h"

void foo()
{
    std::cout << "Hello, foo from adapterA" << std::endl;
}

adapter/adapterA/src/Makefile.am

# Process this file with automake to produce Makefile.in

# Adapter .so version
ADAPTER_SO_VERSION = 0:0:0

AM_CXXFLAGS = \
    -I$(top_srcdir)/include \
    -I$(srcdir)/../include \
    @AM_CXXFLAGS@

# Library name
lib_LTLIBRARIES = libadapter-@HELLO_API_VERSION@.la

# Sources
libadapter_@HELLO_API_VERSION@_la_SOURCES = \
    ../../../src/hello.cpp \
    foo.cpp

# Linker flags    
libadapter_@HELLO_API_VERSION@_la_LDFLAGS = \
    -version-info $(ADAPTER_SO_VERSION)

# Include directory and headers
libadapter_@HELLO_API_VERSION@_la_includedir = \
    $(exec_prefix)/include/adapter/adapterA
libadapter_@HELLO_API_VERSION@_la_include_HEADERS = \
    ../include/foo.h

# Library install directory
libdir = $(exec_prefix)/lib/adapter/adapterA

adapter/adapterB/Makefile.amadapter/adapterB/include/foo.h与他们的A等价物相同。

adapter/adapterB/src/foo.cpp

#include <iostream>

#include "foo.h"

void foo()
{
    std::cout << "Hello, foo from adapterB" << std::endl;
}

adapter/adapterB/src/Makefile.am

# Process this file with automake to produce Makefile.in

# Adapter .so version
ADAPTER_SO_VERSION = 0:0:0

AM_CXXFLAGS = \
    -I$(top_srcdir)/include \
    -I$(srcdir)/../include \
    @AM_CXXFLAGS@

# Library name
lib_LTLIBRARIES = libadapter-@HELLO_API_VERSION@.la

# Sources
libadapter_@HELLO_API_VERSION@_la_SOURCES = \
    ../../../src/hello.cpp \
    foo.cpp

# Linker flags    
libadapter_@HELLO_API_VERSION@_la_LDFLAGS = \
    -version-info $(ADAPTER_SO_VERSION)

# Include directory and headers
libadapter_@HELLO_API_VERSION@_la_includedir = \
    $(exec_prefix)/include/adapter/adapterB
libadapter_@HELLO_API_VERSION@_la_include_HEADERS = \
    ../include/foo.h

# Library install directory
libdir = $(exec_prefix)/lib/adapter/adapterB

include/hello.h

#ifndef HELLO_H_
#define HELLO_H_

void hello();

#endif

src/hello.cpp

#include <iostream>

#include "hello.h"

void hello()
{
    std::cout << "Hello, world!" << std::endl;
}

src/helloconf.sh.in

#!/bin/bash

echo @prefix@

src/Makefile.am

# Process this file with automake to produce Makefile.in

# Look for additional autoconf macros in the m4 subdirectory
ACLOCAL_AMFLAGS = \
    -I m4 \
    @ACLOCAL_FLAGS@

# Compiler flags
AM_CXXFLAGS = \
    -I$(top_srcdir)/include \
    @AM_CXXFLAGS@

# Library name
lib_LTLIBRARIES = libhello-@HELLO_API_VERSION@.la

# Sources
libhello_@HELLO_API_VERSION@_la_SOURCES = \
    hello.cpp

# Libraries
libhello_@HELLO_API_VERSION@_la_LDFLAGS = \
    -version-info $(HELLO_SO_VERSION)
libhello_@HELLO_API_VERSION@_la_LIBADD = @LTLIBOBJS@

# Include directory and headers
libhello_@HELLO_API_VERSION@_la_includedir = $(includedir)

libhello_@HELLO_API_VERSION@_la_include_HEADERS = \
    $(top_srcdir)/include/hello.h

# Data
helloconf_DATA = helloconf.sh
helloconfdir = $(exec_prefix)/bin
EXTRA_DIST = $(helloconf_DATA)

P.S。:我知道上传档案可能更好,但我想将所有内容保存在一个地方。