//
// aegis - project change supervisor
// Copyright (C) 2006-2012, 2014 Peter Miller;
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License, version 3, as
// published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
//
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
nstring_list target::scripts;
target::~target()
{
}
void
target::set_flavour(const nstring &name)
{
flavour::pointer fp = flavour::factory(name, *this);
fp->set_process();
processing.register_default(process_item_extra_dist::create(*this));
}
static void
check_state(change::pointer cp)
{
cstate_ty *csp = cp->cstate_get();
assert(csp);
string_ty *d = 0;
switch (csp->state)
{
case cstate_state_being_integrated:
d = cp->integration_directory_get(false);
break;
case cstate_state_awaiting_review:
case cstate_state_awaiting_integration:
case cstate_state_being_reviewed:
case cstate_state_being_developed:
d = cp->development_directory_get(0);
break;
default:
change_fatal(cp, 0, i18n("bad cd, no dir"));
// NOTREACHED
}
chdir(d->str_text);
}
target::target(change_identifier &a_cid) :
cid(a_cid),
ostate(ostate_reset)
{
check_state(cid.get_cp());
// FIXME: output_file::create for the --output=filename option.
op = output_stdout::create();
op = output_filter_set_width::create(op, 80);
//
// Initialise the view path used to locate actual files in the project
// baseline, and not in the change set's development directory.
//
nstring_list dirs;
cid.get_cp()->search_path_get(dirs, true);
for (size_t k = 0; k < dirs.size(); ++k)
view_path.push_back(dirs[k] + "/");
//
// See if the project is known to install a shared library. We use the
// "aemakegen:libtool=true" project attribute as a proxy for this.
//
if (cid.get_cp()->pconf_attributes_get_boolean("aemakegen:libtool"))
{
data.set_use_libtool();
}
if (data.use_libtool())
{
//
// The debian folk take exception to the "almost
// always useless" *.la files install by libtool.
// So this defaults to false.
//
if (cid.get_cp()->pconf_attributes_get_boolean("aemakegen:libtool-la"))
data.set_use_lib_la_files();
//
// We also need to get the version information to use with the
// shared file.
//
nstring text =
cid.get_cp()->pconf_attributes_find("aemakegen:version-info");
data.set_version_info(text);
}
}
void
target::script(const nstring &arg)
{
scripts.push_back(arg);
}
nstring
target::resolve(const nstring &relpath)
{
if (relpath[0] == '/')
return relpath;
for (size_t j = 0; j < view_path.size(); ++j)
{
nstring path = view_path[j] + relpath;
if (exists(path))
return path;
}
return relpath;
}
bool
target::exists(const nstring &path)
{
return (access(path.c_str(), F_OK) == 0);
}
void
target::process(const nstring_list &filenames)
{
manifest = filenames;
// Processing the list of file names has several phases:
//
// 1. pre-preprocess
// no text is emitted at this stage
// 1a. set library directory
// 1b. configure.ac
// 1c. noinst file attribute
// 1d. master include file, and closure
process1(manifest);
// 2. preprocess -- this stage figures out file lists
// no text is emitted at this stage
// 2a. preprocess_begin()
// 2b. preprocess per file
// 2c. preprocess_end()
process2(manifest);
// 3. process -- this stage emits text
// *this stage is a virtual method*
// 3a. begin()
// 3b. process per file
// 3c. end()
process3(manifest);
}
static bool
program_name_implies_noinst(const nstring &base)
{
assert(base == base.basename());
return
(
base.starts_with("test_")
||
base.starts_with("test-")
||
base.starts_with("noinst_")
||
base.starts_with("noinst-")
);
}
void
target::process1(const nstring_list &filenames)
{
//
// Before we preprocess anything, we locate the project's library
// directory, if the project has one.
//
data.set_library_directory(cid, filenames);
//
// 1. Set the list of files that are *not* to be installed.
// 2. Grab information from the configure.ac file.
//
for (size_t j = 0; j < filenames.size(); ++j)
{
nstring filename = filenames[j];
//
// Progess the configure.ac file, to see if there is any useful
// information to be gleaned from it.
//
nstring base = filename.basename();
if
(
base == "configure.ac"
||
base == "configure.ac.in"
||
base == "configure.in"
)
{
preprocess_configure_dot_ac(filename);
}
// We need to find all the program directories.
if (is_a_source_file(filename) && filename_implies_progname(filename))
{
data.remember_progdir(filename.dirname());
}
//
// Remember the names of the files that are not to be installed,
// taken from the "aemakegen:noinst" file attribute.
//
if (file_attr_noinst(filename))
{
if (filename_implies_is_a_script(filename))
{
nstring prog = filename.basename();
if (filename.ends_with(".in"))
prog = prog.trim_extension();
if (extension_implies_script(prog))
prog = prog.trim_extension();
data.remember_explicit_noinst(prog);
}
else
{
nstring prog = progname_from_dir_of(filename);
data.remember_explicit_noinst(prog);
}
}
else
{
//
// Some file names imply that the program is not to be installed.
//
if (filename_implies_is_a_script(filename))
{
nstring prog = filename.basename();
if (filename.ends_with(".in"))
prog = prog.trim_extension();
if (extension_implies_script(prog))
prog = prog.trim_extension();
if (program_name_implies_noinst(prog))
data.remember_explicit_noinst(prog);
}
else
{
nstring progname = progname_from_dir_of(filename);
if (program_name_implies_noinst(progname))
data.remember_explicit_noinst(progname);
}
}
}
//
// The master include file, and the files it includes, are all installable.
// The master include file's name is "lib/lib.h"
//
nstring master_include_file =
data.get_library_directory() + "/" + data.get_library_name() + ".h";
if (filenames.member(master_include_file))
{
preprocess_include_headers(master_include_file);
}
else
{
master_include_file =
data.get_library_directory() + "/" + get_project_name() + ".h";
if (filenames.member(master_include_file))
{
preprocess_include_headers(master_include_file);
}
}
}
void
target::process2(const nstring_list &filenames)
{
//
// Preprocess per file:
//
// Let the derived classes look at the files.
//
process2_begin();
processing.run_preprocess(filenames);
process2_end();
// done with preprocessing stage
data.notify_preprocess_complete();
}
void
target::process2_begin(void)
{
// The default implementation does nothing.
trace(("%s\n", __PRETTY_FUNCTION__));
}
void
target::process2_end(void)
{
// remember to clean up after programs
{
nstring_list programs = data.get_programs();
for (size_t j = 0; j < programs.size(); ++j)
{
nstring prog = programs[j];
{
nstring filename = "bin/" + prog + data.exeext();
data.remember_all_bin(filename);
}
if (is_installable(prog))
{
nstring filename =
(
"$(bindir)/"
+
data.get_program_prefix()
+
prog
+
data.get_program_suffix()
+
data.exeext()
);
data.remember_install_bin(filename);
}
}
}
// remember to clean up after libraries
{
nstring_list dirs = data.get_list_of_library_directories();
for (size_t j = 0; j < dirs.size(); ++j)
{
nstring library_dirname = dirs[j];
nstring library_libname = library_dirname;
if (library_libname == "lib")
library_libname = get_project_name();
if (!library_libname.starts_with("lib"))
library_libname = "lib" + library_libname;
nstring filename =
library_dirname + "/" + library_libname + "." + data.libext();
data.remember_clean_obj_file(filename);
// otherwise always assume it is no-inst and static.
bool shared =
(
data.use_libtool()
&&
library_libname == get_library_libname()
);
if (shared)
{
data.remember_clean_obj_file(filename.trim_extension() + ".a");
data.remember_dist_clean_dir(filename.dirname() + "/.libs");
nstring fn = "$(libdir)/" + filename.basename();
data.remember_install_libdir(fn);
}
}
}
// The distclean target should remove the config.h file, as well.
{
nstring libdir = data.get_library_directory();
if (!libdir.empty())
{
data.remember_dist_clean_file(libdir + "/config.h");
}
}
}
void
target::process3(const nstring_list &filenames)
{
process3_begin();
processing.run_process(filenames);
process3_end();
}
void
target::process3_begin(void)
{
// The default implementation does nothing.
trace(("%s\n", __PRETTY_FUNCTION__));
}
void
target::process3_end(void)
{
// The default implementation does nothing.
trace(("%s\n", __PRETTY_FUNCTION__));
}
bool
target::filename_implies_is_a_script(const nstring &fn)
{
if (fn.gmatch(scripts))
return true;
return
(
(fn.starts_with("script/") || fn.starts_with("scripts/"))
&&
(extension_implies_script(fn) || is_hash_bang(fn))
);
}
bool
target::trim_script_suffix(void)
const
{
// FIXME: this may need to be controlled from a command line option,
// one day.
return true;
}
nstring
target::get_project_name(void)
const
{
return nstring(cid.get_pp()->trunk_get()->name_get());
}
nstring
target::get_project_version(void)
const
{
return cid.get_cp()->version_get();
}
static bool
ac_lang_cplusplus(const nstring &line)
{
return
(
line.starts_with("AC_LANG_CPLUSPLUS")
||
line.starts_with("AC_LANG(C++)")
||
line.starts_with("AC_LANG([C++])")
);
}
static bool
ac_lang_c(const nstring &line)
{
return
(
line.starts_with("AC_LANG_C")
||
line.starts_with("AC_LANG(C)")
||
line.starts_with("AC_LANG([C])")
);
}
void
target::preprocess_configure_dot_ac(const nstring &fn)
{
nstring path = resolve(fn);
FILE *fp = fopen(path.c_str(), "r");
if (!fp)
{
nstring fn2 = fn + ".in";
path = resolve(fn2);
fp = fopen(path.c_str(), "r");
}
if (!fp)
return;
for (;;)
{
char cline[2000];
if (!fgets(cline, sizeof(cline), fp))
break;
nstring line(cline);
//
// Check whether or not the project installs internationalisation and
// localisation files.
//
if
(
line.starts_with("AC_CHECK_PROGS(MSGFMT,")
||
line.starts_with("AC_CHECK_PROGS(MSGCAT,")
)
{
data.set_use_i18n();
}
if (line.starts_with("AC_SUBST(NLSDIR)"))
{
data.set_have_nlsdir();
data.set_use_i18n();
}
//
// Check whether the project needs X11 to build.
//
if (line.starts_with("AC_PATH_XTRA"))
data.set_use_x11();
if (line.starts_with("AC_PROG_LEX"))
data.set_have_lex();
if (line.starts_with("AC_PROG_YACC"))
data.set_have_yacc();
if (line.starts_with("AC_PROG_RANLIB"))
data.set_have_ranlib();
if (line.starts_with("AC_CHECK_PROGS(AR,"))
data.set_have_ar();
if (line.starts_with("AC_CHECK_PROGS(GROFF,"))
data.set_have_groff();
if (line.starts_with("AC_CHECK_PROGS(SOELIM,"))
data.set_have_soelim();
if (line.starts_with("AC_OBJEXT"))
data.set_objext();
if (line.starts_with("AC_LIBEXT"))
data.set_libext();
if (line.starts_with("AC_EXEEXT"))
data.set_exeext();
if (ac_lang_cplusplus(line))
data.set_seen_c_plus_plus();
else if (ac_lang_c(line))
data.set_seen_c();
if (line.starts_with("dnl! PROGRAM_PREFIX"))
data.set_program_prefix();
if (line.starts_with("dnl! PROGRAM_SUFFIX"))
data.set_program_suffix();
}
fclose(fp);
}
bool
target::is_installable(const nstring &name)
{
return !data.is_explicit_noinst(name);
}
bool
target::file_attr_noinst(const nstring &filename)
{
fstate_src_ty *src = cid.get_cp()->file_find(filename, view_path_extreme);
return
(
src
&&
src->attribute
&&
attributes_list_find_boolean(src->attribute, "aemakegen:noinst")
);
}
bool
target::is_hash_bang(const nstring &filename)
{
nstring path = resolve(filename);
FILE *fp = fopen(path.c_str(), "r");
if (!fp)
{
nstring fn2 = filename + ".in";
path = resolve(fn2);
fp = fopen(path.c_str(), "r");
}
if (!fp)
return false;
int c1 = getc(fp);
int c2 = getc(fp);
fclose(fp);
return (c1 == '#' && c2 == '!');
}
bool
target::contains_dot_so_directive(const nstring &filename)
{
nstring path = resolve(filename);
FILE *fp = fopen(path.c_str(), "r");
if (!fp)
return false;
char state = '\n';
for (;;)
{
int c = getc(fp);
switch (c)
{
case EOF:
fclose(fp);
return false;
case '\n':
state = '\n';
break;
case '.':
state = (state == '\n' ? '.' : 'X');
break;
case 's':
state = (state == '.' ? 's' : 'X');
break;
case 'o':
state = (state == 's' ? 'o' : 'X');
break;
case ' ':
if (state == '.')
break;
if (state == 'o')
{
fclose(fp);
return true;
}
state = 'X';
break;
default:
state = 'X';
break;
}
}
}
bool
target::contains_dot_xx_directive(const nstring &filename)
{
nstring path = resolve(filename);
FILE *fp = fopen(path.c_str(), "r");
if (!fp)
return false;
for (;;)
{
char line[100];
if (!fgets(line, sizeof(line), fp))
{
fclose(fp);
return false;
}
if (strlen(line) > 6 && 0 == memcmp(line, ".XX ", 4))
{
fclose(fp);
return true;
}
}
}
nstring
target::get_library_libname(void)
const
{
nstring result = data.get_library_name();
if (result == "lib")
result = get_project_name();
if (!result.starts_with("lib"))
result = "lib" + result;
return result;
}
void
target::warning_this_file_is_generated(void)
{
warning_this_file_is_generated(op);
ostate = ostate_comment;
}
void
target::warning_this_file_is_generated(const output::pointer &fp)
const
{
trace(("%s {\n", __PRETTY_FUNCTION__));
output::pointer op2 = output_filter_prefix::create(fp, "# ");
op2->fputs
(
"\n"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
"\n"
" W W A RRRR N N III N N III N N GGG\n"
" W W A A R R NN N I NN N I NN N G G\n"
" W W A A RRRR N N N I N N N I N N N G\n"
" W W W AAAAA R R N NN I N NN I N NN G GG\n"
" W W W A A R R N N I N N I N N G G\n"
" W W A A R R N N III N N III N N GGG\n"
"\n"
);
{
output::pointer op3 = output_filter_wrap_simple::create(op2);
op3->fputs
(
"Warning: DO NOT send patches which fix this file. IT IS NOT "
"the original source file. This file is GENERATED from the "
"Aegis repository file manifest. If you find a bug in this "
"file, it could well be an Aegis bug.\n"
);
}
op2->fputs
(
"\n"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
"\n"
);
trace(("}\n"));
}
void
target::register_process(const process_item::pointer &pip)
{
processing.register_process_item(pip);
}
void
target::register_process_front(const process_item::pointer &pip)
{
processing.register_process_item_front(pip);
}
void
target::location_comment(const char *file, int line)
{
if (!debug)
return;
ostate_become(ostate_comment);
op->fprintf
(
"#line %d %s\n",
line,
nstring(file).quote_c().c_str()
);
}
#define OPAIR(a, b) ((a) * 8 + (b))
void
target::ostate_become(ostate_t new_ostate)
{
switch (OPAIR(ostate, new_ostate))
{
case OPAIR(ostate_reset, ostate_comment):
case OPAIR(ostate_reset, ostate_assignment):
case OPAIR(ostate_reset, ostate_rule):
case OPAIR(ostate_comment, ostate_assignment):
case OPAIR(ostate_comment, ostate_rule):
case OPAIR(ostate_assignment, ostate_assignment):
break;
case OPAIR(ostate_comment, ostate_comment):
case OPAIR(ostate_assignment, ostate_comment):
case OPAIR(ostate_assignment, ostate_rule):
case OPAIR(ostate_rule, ostate_comment):
case OPAIR(ostate_rule, ostate_assignment):
case OPAIR(ostate_rule, ostate_rule):
op->fputc('\n');
break;
}
ostate = new_ostate;
}
void
target::print_comment(const nstring &text)
{
ostate_become(ostate_comment);
output::pointer op2 = output_filter_prefix::create(op, "# ");
output::pointer op3 = output_filter_wrap_simple::create(op2);
op3->fputs(text);
}
void
target::print_empty_assignment(const nstring &name)
{
ostate_become(ostate_assignment);
op->fputs(name);
op->fputs(" =\n");
}
void
target::print_assignment(const nstring &name, const nstring &value)
{
nstring_list values;
values.push_back(value);
print_assignment(name, values);
}
void
target::print_assignment(const nstring &name,
const nstring_list &value)
{
if (value.empty())
return;
ostate_become(ostate_assignment);
op->fputs(name);
op->fputs(" =");
for (size_t j = 0; j < value.size(); ++j)
{
op->fputc(' ');
op->fputs(value[j]);
}
op->fputc('\n');
}
void
target::print_assignment_sorted(const nstring &name, const nstring_list &value)
{
nstring_list value2 = value;
value2.sort();
print_assignment(name, value2);
}
void
target::print_rule(const nstring_list &lhs, const nstring_list &rhs,
const nstring_list &body)
{
assert(!lhs.empty() && "no target given");
if (rhs.empty() && body.empty())
return;
ostate_become(ostate_rule);
nstring_list lhs2 = lhs;
lhs2.sort();
for (size_t j = 0; j < lhs2.size(); ++j)
{
if (j)
op->fputc(' ');
op->fputs(lhs2[j]);
}
op->fputc(':');
nstring_list rhs2 = rhs;
rhs2.sort();
for (size_t j = 0; j < rhs2.size(); ++j)
{
op->fputc(' ');
op->fputs(rhs2[j]);
}
op->fputc('\n');
for (size_t j = 0; j < body.size(); ++j)
{
op->fputs("\t");
op->fputs(body[j]);
op->fputc('\n');
}
}
void
target::print_rule(const nstring &lhs, const nstring &rhs)
{
nstring_list lhs2;
lhs2.push_back(lhs);
nstring_list rhs2;
rhs2.push_back(rhs);
nstring_list body;
print_rule(lhs2, rhs2, body);
}
void
target::print_clean_file_rule(const nstring &lhs,
const nstring_list &rhs, const nstring_list &files)
{
nstring_list files2 = files;
files2.sort();
ostate_become(ostate_rule);
op->fputs(lhs);
op->fputc(':');
for (size_t j = 0; j < rhs.size(); ++j)
{
op->fputc(' ');
op->fputs(rhs[j]);
}
op->fputc('\n');
if (!files2.empty())
{
output::pointer op2 = output_filter_prefix::create(op, "\trm -f ");
output::pointer op3 = output_filter_wrap_simple::create(op2);
for (size_t j = 0; j < files2.size(); ++j)
{
if (j)
op3->fputc(' ');
op3->fputs(files2[j]);
}
op3->fputc('\n');
}
}
void
target::print_clean_dirs_rule(const nstring &lhs,
const nstring_list &rhs, const nstring_list &dirs1)
{
nstring_list dirs = dirs1;
dirs.sort();
ostate_become(ostate_rule);
op->fputs(lhs);
op->fputc(':');
nstring_list rhs2 = rhs;
rhs2.sort();
for (size_t j = 0; j < rhs2.size(); ++j)
{
op->fputc(' ');
op->fputs(rhs2[j]);
}
op->fputc('\n');
if (!dirs.empty())
{
output::pointer op2 = output_filter_prefix::create(op, "\trm -rf ");
output::pointer op3 = output_filter_wrap_simple::create(op2);
for (size_t j = 0; j < dirs.size(); ++j)
{
if (j)
op3->fputc(' ');
op3->fputs(dirs[j]);
}
op3->fputc('\n');
}
}
bool
target::is_an_include_candidate(const nstring &fn)
const
{
return
(
manifest.member(fn)
||
data.get_built_sources().member(fn)
||
fn.ends_with(".fmtgen.h")
||
fn.ends_with(".yacc.h")
||
manifest.member(fn + ".in")
);
}
nstring_list
target::c_include_dependencies(const nstring &ifn)
{
trace(("%s\n", __PRETTY_FUNCTION__));
nstring_list result;
result.push_back(ifn);
for (size_t j = 0; j < result.size(); ++j)
c_include_dependencies(result, result[j]);
// we have to be sure the files actually exist
// and we may need some heuristics to do it
nstring_list temp;
for (size_t j = 0; j < result.size(); ++j)
{
nstring ofn = result[j];
if (is_an_include_candidate(ofn))
temp.push_back(ofn);
}
temp.sort();
return temp;
}
static inline bool
safe_isspace(int c)
{
return isspace((unsigned char)c);
}
void
target::c_include_dependencies(nstring_list &results,
const nstring &fn)
{
trace(("%s\n", __PRETTY_FUNCTION__));
nstring path = resolve(fn);
FILE *fp = fopen(path.c_str(), "r");
if (!fp)
{
// heuristic to cope with "etc/libdir.h.in"
// otherwise not being found
path = resolve(fn + ".in");
fp = fopen(path.c_str(), "r");
if (!fp)
return;
}
for (;;)
{
char line[2000];
if (!fgets(line, sizeof(line), fp))
break;
char *cp = line;
while (safe_isspace(*cp))
++cp;
if (*cp == '#')
c_directive(cp, results);
}
fclose(fp);
}
void
target::c_directive(const char *s, nstring_list &results)
{
trace(("%s\n", __PRETTY_FUNCTION__));
//
// see if it is a #include directive
//
assert(*s == '#');
++s;
while (safe_isspace(*s))
++s;
if (memcmp(s, "include", 7))
return;
s += 7;
while (safe_isspace(*s))
++s;
//
// figure which type
// ignore broken directives
//
int right = 0;
switch (*s++)
{
default:
return;
case '"':
right = '"';
break;
case '<':
right = '>';
break;
}
//
// find the end of the filename
// ignore broken directives
// ignore anything on the end of the line
//
const char *filename = s;
while (*s != right)
{
if (!*s || *s == '\n')
return;
++s;
}
//
// extract the path
// ignore broken directives
//
if (s == filename)
return;
nstring path(filename, s - filename);
//
// remember this path for later scanning
//
results.push_back_unique(path);
}
void
target::roff_include_dependencies(nstring_list &results,
const nstring &fn)
{
trace(("%s\n", __PRETTY_FUNCTION__));
nstring path = resolve(fn);
FILE *fp = fopen(path.c_str(), "r");
if (!fp)
{
// heuristic to cope with "etc/libdir.so.in"
// otherwise not being found
path = resolve(fn + ".in");
fp = fopen(path.c_str(), "r");
if (!fp)
return;
}
for (;;)
{
char line[2000];
if (!fgets(line, sizeof(line), fp))
break;
nstring_list words;
words.split(nstring(line));
if (words.size() >= 2 && words[0] == ".so")
results.push_back_unique(words[1]);
}
fclose(fp);
}
nstring_list
target::roff_include_dependencies(const nstring &fn)
{
trace(("%s\n", __PRETTY_FUNCTION__));
nstring_list result;
result.push_back(fn);
for (size_t j = 0; j < result.size(); ++j)
roff_include_dependencies(result, result[j]);
// we have to be sure the files actually exist
// and we may need some heuristics to do it
nstring_list temp;
for (size_t j = 0; j < result.size(); ++j)
{
nstring ofn = result[j];
if (is_an_include_candidate(ofn))
temp.push_back(ofn);
}
temp.sort();
return temp;
}
void
target::emit_static_library_rules(const nstring &name)
{
nstring the_library_directory = name;
nstring the_library_libname = name;
if (the_library_libname == "lib")
the_library_libname = get_project_name();
if (!the_library_libname.starts_with("lib"))
the_library_libname = "lib" + the_library_libname;
emit_library_rules(the_library_directory, the_library_libname, false);
}
void
target::emit_library_rules(const nstring &the_library_directory,
const nstring &the_library_libname, bool is_shared)
{
const nstring_list &objref =
data.get_object_files_by_dir(the_library_directory);
if (objref.empty())
return;
nstring src =
the_library_directory + "/" + the_library_libname + "." + data.libext();
nstring dst = "$(libdir)/" + the_library_libname + "." + data.libext();
nstring dst_la = "$(libdir)/" + the_library_libname + ".la";
// Print a make assignment containing all of the object files.
// We sort the list for aesthetics, and also for predictable
// results for automatic testing.
location_comment(__FILE__, __LINE__);
print_assignment_sorted(the_library_directory + "_obj", objref);
if (is_shared)
{
nstring objs = "$(" + the_library_directory + "_obj)";
nstring src_dir = src.dirname();
nstring dst_dir = dst.dirname();
//
// Link the shared library
//
{
nstring_list lhs;
lhs.push_back(src);
nstring_list rhs;
rhs.push_back(objs);
nstring_list body;
body.push_back("rm -f $@");
nstring command = "$(LIBTOOL) --mode=link ";
if (data.seen_c_plus_plus())
command += "--tag=CXX $(CXX) $(CPPFLAGS) $(CXXFLAGS)";
else
command += "--tag=CC $(CC) $(CPPFLAGS) $(CFLAGS)";
command += " $(LDFLAGS) -o $@ " + objs + " $(LIBS)";
//
// The Debian Policy Manual doesn't like -rpath, and they
// have some good reasons, but the package will not build
// without it.
//
command += " -rpath $(libdir)";
command += " -version-info " + data.get_version_info();
body.push_back(command);
location_comment(__FILE__, __LINE__);
print_rule(lhs, rhs, body);
}
//
// Install the shared library.
//
{
print_comment
(
"\n"
"The install of the *.la file automatically causes "
"\"$(LIBTOOL) --mode=install\" to install the *.a and *.so* "
"files as well, which is why you don't see them explicitly "
"mentioned here.\n"
"\n"
);
nstring_list lhs;
lhs.push_back(dst);
nstring_list rhs;
rhs.push_back(src);
rhs.push_back(make_pseudo_dir_for(dst));
nstring_list body;
assert(data.need_install_data_macro());
body.push_back
(
"$(LIBTOOL) --mode=install $(INSTALL_DATA) " + src + " $@"
);
location_comment(__FILE__, __LINE__);
print_rule(lhs, rhs, body);
}
}
else
{
nstring objs = "$(" + the_library_directory + "_obj)";
//
// Link the noinst library
//
location_comment(__FILE__, __LINE__);
nstring_list lhs;
lhs.push_back(src);
nstring_list rhs;
rhs.push_back(objs);
nstring_list body;
body.push_back("rm -f $@");
body.push_back("$(AR) qc $@ " + objs);
body.push_back("$(RANLIB) $@");
print_rule(lhs, rhs, body);
}
}
void
target::process_item_aegis_fmtgen(const nstring &fn)
{
trace(("%s\n", __PRETTY_FUNCTION__));
nstring stem = fn.trim_extension();
nstring oc = stem + ".fmtgen.cc";
nstring oh = stem + ".fmtgen.h";
processing.run_process(oc);
processing.run_process(oh);
}
void
target::process_item_aegis_lib_doc(const nstring &)
{
// The default implementation does nothing.
trace(("%s\n", __PRETTY_FUNCTION__));
}
void
target::process_item_aegis_lib_else(const nstring &)
{
// The default implementation does nothing.
trace(("%s\n", __PRETTY_FUNCTION__));
}
void
target::process_item_aegis_lib_icon2(const nstring &)
{
// The default implementation does nothing.
trace(("%s\n", __PRETTY_FUNCTION__));
}
void
target::process_item_aegis_lib_junk(const nstring &)
{
// The default implementation does nothing.
trace(("%s\n", __PRETTY_FUNCTION__));
}
void
target::process_item_aegis_lib_sh(const nstring &)
{
// The default implementation does nothing.
trace(("%s\n", __PRETTY_FUNCTION__));
}
void
target::process_item_aegis_test_base64(const nstring &fn)
{
// The default implementation resubmits the derived file,
// without printing anything
trace(("%s\n", __PRETTY_FUNCTION__));
nstring fn2 = fn.trim_extension();
processing.run_process(fn2);
}
void
target::process_item_configure_ac_in(const nstring &fn)
{
// The default implementation resubmits the derived file,
// without printing anything
nstring fn2 = nstring(fn.c_str(), fn.size() - 3);
// now process the result of the rule.
processing.run_process(fn2);
}
void
target::process_item_autoconf(const nstring &fn)
{
// The default implementation resubmits the derived file,
// without printing anything
nstring fn2 = nstring(fn.c_str(), fn.size() - 3);
// now process the result of the rule.
// it could be just about anything.
processing.run_process(fn2);
}
void
target::process_item_c(const nstring &)
{
// The default implementation does nothing.
trace(("%s\n", __PRETTY_FUNCTION__));
}
void
target::process_item_cxx(const nstring &)
{
// The default implementation does nothing.
trace(("%s\n", __PRETTY_FUNCTION__));
}
void
target::process_item_datadir(const nstring &)
{
// The default implementation does nothing.
trace(("%s\n", __PRETTY_FUNCTION__));
}
void
target::process_item_datarootdir(const nstring &)
{
// The default implementation does nothing.
trace(("%s\n", __PRETTY_FUNCTION__));
}
void
target::process_item_etc_man(const nstring &)
{
// The default implementation does nothing.
trace(("%s\n", __PRETTY_FUNCTION__));
}
void
target::process_item_etc_msgfmt_sh(const nstring &)
{
// The default implementation does nothing.
trace(("%s\n", __PRETTY_FUNCTION__));
}
void
target::process_item_etc_profile(const nstring &)
{
// The default implementation does nothing.
trace(("%s\n", __PRETTY_FUNCTION__));
}
void
target::process_item_extra_dist(const nstring &)
{
// The default implementation does nothing.
trace(("%s\n", __PRETTY_FUNCTION__));
}
void
target::process_item_flexible(const nstring &)
{
// The default implementation does nothing.
trace(("%s\n", __PRETTY_FUNCTION__));
}
void
target::process_item_i18n(const nstring &)
{
// The default implementation does nothing.
trace(("%s\n", __PRETTY_FUNCTION__));
}
void
target::process_item_include(const nstring &)
{
// The default implementation does nothing.
trace(("%s\n", __PRETTY_FUNCTION__));
}
void
target::process_item_lex(const nstring &fn)
{
trace(("%s\n", __PRETTY_FUNCTION__));
// The default implementation resubmits the derived file,
// but prints no output.
nstring stem = fn.trim_extension();
nstring oc = stem + ".lex.c";
if (data.seen_c_plus_plus())
oc += "c";
processing.run_process(oc);
}
void
target::process_item_libdir(const nstring &)
{
// The default implementation does nothing.
trace(("%s\n", __PRETTY_FUNCTION__));
}
void
target::process_item_library(const nstring &)
{
// The default implementation does nothing.
trace(("%s\n", __PRETTY_FUNCTION__));
}
void
target::process_item_man_page(const nstring &)
{
// The default implementation does nothing.
trace(("%s\n", __PRETTY_FUNCTION__));
}
void
target::process_item_pkgconfig(const nstring &)
{
// The default implementation does nothing.
trace(("%s\n", __PRETTY_FUNCTION__));
}
void
target::process_item_scripts(const nstring &)
{
// The default implementation does nothing.
trace(("%s\n", __PRETTY_FUNCTION__));
}
void
target::process_item_test_sh(const nstring &)
{
// The default implementation does nothing.
trace(("%s\n", __PRETTY_FUNCTION__));
}
void
target::process_item_uudecode(const nstring &fn)
{
// The default implementation resubmits the derived file,
// without printing anything
trace(("%s\n", __PRETTY_FUNCTION__));
nstring fn2 = fn.trim_extension();
processing.run_process(fn2);
}
void
target::process_item_yacc(const nstring &fn)
{
trace(("%s\n", __PRETTY_FUNCTION__));
// The default implementation resubmits derived files,
// but prints no output.
nstring stem = fn.trim_extension();
nstring oc = stem + ".yacc.c";
if (data.seen_c_plus_plus())
oc += "c";
nstring oh = stem + ".yacc.h";
processing.run_process(oc);
processing.run_process(oh);
}
bool
target::file_is_in_manifest(const nstring &filename)
const
{
return manifest.member(filename);
}
// vim: set ts=8 sw=4 et :