Initial CVS checkin of gold
This commit is contained in:
parent
c17d87de17
commit
bae7f79e03
|
@ -0,0 +1,9 @@
|
|||
elfcpp is a C++ library for reading and writing ELF information. This
|
||||
was written to support gold, the ELF linker, and may not be generally
|
||||
useful.
|
||||
|
||||
elfcpp does not do file I/O. It deals only with offsets and memory
|
||||
data.
|
||||
|
||||
For efficiency, most accessors are templates with two arguments: the
|
||||
ELF file class (32 or 64 bits) and the endianness.
|
|
@ -0,0 +1,599 @@
|
|||
// elfcpp.h -- main header file for elfcpp -*- C++ -*-
|
||||
|
||||
// This is the external interface for elfcpp.
|
||||
|
||||
#ifndef ELFCPP_H
|
||||
#define ELFCPP_H
|
||||
|
||||
#include "elfcpp_config.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace elfcpp
|
||||
{
|
||||
|
||||
// Basic ELF types.
|
||||
|
||||
// These types are always the same size.
|
||||
|
||||
typedef uint16_t Elf_Half;
|
||||
typedef uint32_t Elf_Word;
|
||||
typedef int32_t Elf_Sword;
|
||||
typedef uint64_t Elf_Xword;
|
||||
typedef int64_t Elf_Sxword;
|
||||
|
||||
// These types vary in size depending on the ELF file class. The
|
||||
// template parameter should be 32 or 64.
|
||||
|
||||
template<int size>
|
||||
struct Elf_types
|
||||
{
|
||||
// Dummy types which should not be used.
|
||||
typedef unsigned char Elf_Addr;
|
||||
typedef unsigned char Elf_Off;
|
||||
// WXword is for fields which are Elf32_Word and Elf64_Xword.
|
||||
typedef unsigned char Elf_WXword;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Elf_types<32>
|
||||
{
|
||||
typedef uint32_t Elf_Addr;
|
||||
typedef uint32_t Elf_Off;
|
||||
typedef uint32_t Elf_WXword;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Elf_types<64>
|
||||
{
|
||||
typedef uint64_t Elf_Addr;
|
||||
typedef uint64_t Elf_Off;
|
||||
typedef uint64_t Elf_WXword;
|
||||
static const int ehdr_size;
|
||||
static const int shdr_size;
|
||||
static const int sym_size;
|
||||
};
|
||||
|
||||
// Offsets within the Ehdr e_ident field.
|
||||
|
||||
const int EI_MAG0 = 0;
|
||||
const int EI_MAG1 = 1;
|
||||
const int EI_MAG2 = 2;
|
||||
const int EI_MAG3 = 3;
|
||||
const int EI_CLASS = 4;
|
||||
const int EI_DATA = 5;
|
||||
const int EI_VERSION = 6;
|
||||
const int EI_OSABI = 7;
|
||||
const int EI_ABIVERSION = 8;
|
||||
const int EI_PAD = 9;
|
||||
const int EI_NIDENT = 16;
|
||||
|
||||
// The valid values found in Ehdr e_ident[EI_MAG0 through EI_MAG3].
|
||||
|
||||
const int ELFMAG0 = 0x7f;
|
||||
const int ELFMAG1 = 'E';
|
||||
const int ELFMAG2 = 'L';
|
||||
const int ELFMAG3 = 'F';
|
||||
|
||||
// The valid values found in Ehdr e_ident[EI_CLASS].
|
||||
|
||||
enum
|
||||
{
|
||||
ELFCLASSNONE = 0,
|
||||
ELFCLASS32 = 1,
|
||||
ELFCLASS64 = 2
|
||||
};
|
||||
|
||||
// The valid values found in Ehdr e_ident[EI_DATA].
|
||||
|
||||
enum
|
||||
{
|
||||
ELFDATANONE = 0,
|
||||
ELFDATA2LSB = 1,
|
||||
ELFDATA2MSB = 2
|
||||
};
|
||||
|
||||
// The valid values found in Ehdr e_ident[EI_VERSION] and e_version.
|
||||
|
||||
enum
|
||||
{
|
||||
EV_NONE = 0,
|
||||
EV_CURRENT = 1
|
||||
};
|
||||
|
||||
// The valid values found in Ehdr e_ident[EI_OSABI].
|
||||
|
||||
enum ELFOSABI
|
||||
{
|
||||
ELFOSABI_NONE = 0,
|
||||
ELFOSABI_HPUX = 1,
|
||||
ELFOSABI_NETBSD = 2,
|
||||
// ELFOSABI_LINUX is not listed in the ELF standard.
|
||||
ELFOSABI_LINUX = 3,
|
||||
// ELFOSABI_HURD is not listed in the ELF standard.
|
||||
ELFOSABI_HURD = 4,
|
||||
ELFOSABI_SOLARIS = 6,
|
||||
ELFOSABI_AIX = 7,
|
||||
ELFOSABI_IRIX = 8,
|
||||
ELFOSABI_FREEBSD = 9,
|
||||
ELFOSABI_TRU64 = 10,
|
||||
ELFOSABI_MODESTO = 11,
|
||||
ELFOSABI_OPENBSD = 12,
|
||||
ELFOSABI_OPENVMS = 13,
|
||||
ELFOSABI_NSK = 14,
|
||||
ELFOSABI_AROS = 15,
|
||||
// A GNU extension for the ARM.
|
||||
ELFOSABI_ARM = 97,
|
||||
// A GNU extension for the MSP.
|
||||
ELFOSABI_STANDALONE = 255
|
||||
};
|
||||
|
||||
// The valid values found in the Ehdr e_type field.
|
||||
|
||||
enum ET
|
||||
{
|
||||
ET_NONE = 0,
|
||||
ET_REL = 1,
|
||||
ET_EXEC = 2,
|
||||
ET_DYN = 3,
|
||||
ET_CORE = 4,
|
||||
ET_LOOS = 0xfe00,
|
||||
ET_HIOS = 0xfeff,
|
||||
ET_LOPROC = 0xff00,
|
||||
ET_HIPROC = 0xffff
|
||||
};
|
||||
|
||||
// The valid values found in the Ehdr e_machine field.
|
||||
|
||||
enum EM
|
||||
{
|
||||
EM_NONE = 0,
|
||||
EM_M32 = 1,
|
||||
EM_SPARC = 2,
|
||||
EM_386 = 3,
|
||||
EM_68K = 4,
|
||||
EM_88K = 5,
|
||||
// 6 used to be EM_486
|
||||
EM_860 = 7,
|
||||
EM_MIPS = 8,
|
||||
EM_S370 = 9,
|
||||
EM_MIPS_RS3_LE = 10,
|
||||
// 11 was the old Sparc V9 ABI.
|
||||
// 12 through 14 are reserved.
|
||||
EM_PARISC = 15,
|
||||
// 16 is reserved.
|
||||
// Some old PowerPC object files use 17.
|
||||
EM_VPP500 = 17,
|
||||
EM_SPARC32PLUS = 18,
|
||||
EM_960 = 19,
|
||||
EM_PPC = 20,
|
||||
EM_PPC64 = 21,
|
||||
EM_S390 = 22,
|
||||
// 23 through 35 are served.
|
||||
EM_V800 = 36,
|
||||
EM_FR20 = 37,
|
||||
EM_RH32 = 38,
|
||||
EM_RCE = 39,
|
||||
EM_ARM = 40,
|
||||
EM_ALPHA = 41,
|
||||
EM_SH = 42,
|
||||
EM_SPARCV9 = 43,
|
||||
EM_TRICORE = 44,
|
||||
EM_ARC = 45,
|
||||
EM_H8_300 = 46,
|
||||
EM_H8_300H = 47,
|
||||
EM_H8S = 48,
|
||||
EM_H8_500 = 49,
|
||||
EM_IA_64 = 50,
|
||||
EM_MIPS_X = 51,
|
||||
EM_COLDFIRE = 52,
|
||||
EM_68HC12 = 53,
|
||||
EM_MMA = 54,
|
||||
EM_PCP = 55,
|
||||
EM_NCPU = 56,
|
||||
EM_NDR1 = 57,
|
||||
EM_STARCORE = 58,
|
||||
EM_ME16 = 59,
|
||||
EM_ST100 = 60,
|
||||
EM_TINYJ = 61,
|
||||
EM_X86_64 = 62,
|
||||
EM_PDSP = 63,
|
||||
EM_PDP10 = 64,
|
||||
EM_PDP11 = 65,
|
||||
EM_FX66 = 66,
|
||||
EM_ST9PLUS = 67,
|
||||
EM_ST7 = 68,
|
||||
EM_68HC16 = 69,
|
||||
EM_68HC11 = 70,
|
||||
EM_68HC08 = 71,
|
||||
EM_68HC05 = 72,
|
||||
EM_SVX = 73,
|
||||
EM_ST19 = 74,
|
||||
EM_VAX = 75,
|
||||
EM_CRIS = 76,
|
||||
EM_JAVELIN = 77,
|
||||
EM_FIREPATH = 78,
|
||||
EM_ZSP = 79,
|
||||
EM_MMIX = 80,
|
||||
EM_HUANY = 81,
|
||||
EM_PRISM = 82,
|
||||
EM_AVR = 83,
|
||||
EM_FR30 = 84,
|
||||
EM_D10V = 85,
|
||||
EM_D30V = 86,
|
||||
EM_V850 = 87,
|
||||
EM_M32R = 88,
|
||||
EM_MN10300 = 89,
|
||||
EM_MN10200 = 90,
|
||||
EM_PJ = 91,
|
||||
EM_OPENRISC = 92,
|
||||
EM_ARC_A5 = 93,
|
||||
EM_XTENSA = 94,
|
||||
EM_VIDEOCORE = 95,
|
||||
EM_TMM_GPP = 96,
|
||||
EM_NS32K = 97,
|
||||
EM_TPC = 98,
|
||||
// Some old picoJava object files use 99 (EM_PJ is correct).
|
||||
EM_SNP1K = 99,
|
||||
EM_ST200 = 100,
|
||||
EM_IP2K = 101,
|
||||
EM_MAX = 102,
|
||||
EM_CR = 103,
|
||||
EM_F2MC16 = 104,
|
||||
EM_MSP430 = 105,
|
||||
EM_BLACKFIN = 106,
|
||||
EM_SE_C33 = 107,
|
||||
EM_SEP = 108,
|
||||
EM_ARCA = 109,
|
||||
EM_UNICORE = 110,
|
||||
EM_ALTERA_NIOS2 = 113,
|
||||
EM_CRX = 114,
|
||||
// The Morph MT.
|
||||
EM_MT = 0x2530,
|
||||
// DLX.
|
||||
EM_DLX = 0x5aa5,
|
||||
// FRV.
|
||||
EM_FRV = 0x5441,
|
||||
// Infineon Technologies 16-bit microcontroller with C166-V2 core.
|
||||
EM_X16X = 0x4688,
|
||||
// Xstorym16
|
||||
EM_XSTORMY16 = 0xad45,
|
||||
// Renesas M32C
|
||||
EM_M32C = 0xfeb0,
|
||||
// Vitesse IQ2000
|
||||
EM_IQ2000 = 0xfeba,
|
||||
// NIOS
|
||||
EM_NIOS32 = 0xfebb
|
||||
// Old AVR objects used 0x1057 (EM_AVR is correct).
|
||||
// Old MSP430 objects used 0x1059 (EM_MSP430 is correct).
|
||||
// Old FR30 objects used 0x3330 (EM_FR30 is correct).
|
||||
// Old OpenRISC objects used 0x3426 and 0x8472 (EM_OPENRISC is correct).
|
||||
// Old D10V objects used 0x7650 (EM_D10V is correct).
|
||||
// Old D30V objects used 0x7676 (EM_D30V is correct).
|
||||
// Old IP2X objects used 0x8217 (EM_IP2K is correct).
|
||||
// Old PowerPC objects used 0x9025 (EM_PPC is correct).
|
||||
// Old Alpha objects used 0x9026 (EM_ALPHA is correct).
|
||||
// Old M32R objects used 0x9041 (EM_M32R is correct).
|
||||
// Old V850 objects used 0x9080 (EM_V850 is correct).
|
||||
// Old S/390 objects used 0xa390 (EM_S390 is correct).
|
||||
// Old Xtensa objects used 0xabc7 (EM_XTENSA is correct).
|
||||
// Old MN10300 objects used 0xbeef (EM_MN10300 is correct).
|
||||
// Old MN10200 objects used 0xdead (EM_MN10200 is correct).
|
||||
};
|
||||
|
||||
// Special section indices.
|
||||
|
||||
enum
|
||||
{
|
||||
SHN_UNDEF = 0,
|
||||
SHN_LORESERVE = 0xff00,
|
||||
SHN_LOPROC = 0xff00,
|
||||
SHN_HIPROC = 0xff1f,
|
||||
SHN_LOOS = 0xff20,
|
||||
SHN_HIOS = 0xff3f,
|
||||
SHN_ABS = 0xfff1,
|
||||
SHN_COMMON = 0xfff2,
|
||||
SHN_XINDEX = 0xffff,
|
||||
SHN_HIRESERVE = 0xffff
|
||||
};
|
||||
|
||||
// The valid values found in the Shdr sh_type field.
|
||||
|
||||
enum
|
||||
{
|
||||
SHT_NULL = 0,
|
||||
SHT_PROGBITS = 1,
|
||||
SHT_SYMTAB = 2,
|
||||
SHT_STRTAB = 3,
|
||||
SHT_RELA = 4,
|
||||
SHT_HASH = 5,
|
||||
SHT_DYNAMIC = 6,
|
||||
SHT_NOTE = 7,
|
||||
SHT_NOBITS = 8,
|
||||
SHT_REL = 9,
|
||||
SHT_SHLIB = 10,
|
||||
SHT_DYNSYM = 11,
|
||||
SHT_INIT_ARRAY = 14,
|
||||
SHT_FINI_ARRAY = 15,
|
||||
SHT_PREINIT_ARRAY = 16,
|
||||
SHT_GROUP = 17,
|
||||
SHT_SYMTAB_SHNDX = 18,
|
||||
SHT_LOOS = 0x60000000,
|
||||
SHT_HIOS = 0x6fffffff,
|
||||
SHT_LOPROC = 0x70000000,
|
||||
SHT_HIPROC = 0x7fffffff,
|
||||
SHT_LOUSER = 0x80000000,
|
||||
SHT_HIUSER = 0xffffffff,
|
||||
// The remaining values are not in the standard.
|
||||
// List of prelink dependencies.
|
||||
SHT_GNU_LIBLIST = 0x6ffffff7,
|
||||
// Versions defined by file.
|
||||
SHT_SUNW_verdef = 0x6ffffffd,
|
||||
SHT_GNU_verdef = 0x6ffffffd,
|
||||
// Versions needed by file.
|
||||
SHT_SUNW_verneed = 0x6ffffffe,
|
||||
SHT_GNU_verneed = 0x6ffffffe,
|
||||
// Symbol versions,
|
||||
SHT_SUNW_versym = 0x6fffffff,
|
||||
SHT_GNU_versym = 0x6fffffff,
|
||||
};
|
||||
|
||||
// The valid bit flags found in the Shdr sh_flags field.
|
||||
|
||||
enum
|
||||
{
|
||||
SHF_WRITE = 0x1,
|
||||
SHF_ALLOC = 0x2,
|
||||
SHF_EXECINSTR = 0x4,
|
||||
SHF_MERGE = 0x10,
|
||||
SHF_STRINGS = 0x20,
|
||||
SHF_INFO_LINK = 0x40,
|
||||
SHF_LINK_ORDER = 0x80,
|
||||
SHF_OS_NONCONFORMING = 0x100,
|
||||
SHF_GROUP = 0x200,
|
||||
SHF_TLS = 0x400,
|
||||
SHF_MASKOS = 0x0ff00000,
|
||||
SHF_MASKPROC = 0xf0000000
|
||||
};
|
||||
|
||||
// Bit flags which appear in the first 32-bit word of the section data
|
||||
// of a SHT_GROUP section.
|
||||
|
||||
enum
|
||||
{
|
||||
GRP_COMDAT = 0x1,
|
||||
GRP_MASKOS = 0x0ff00000,
|
||||
GRP_MASKPROC = 0xf0000000
|
||||
};
|
||||
|
||||
// Symbol binding from Sym st_info field.
|
||||
|
||||
enum STB
|
||||
{
|
||||
STB_LOCAL = 0,
|
||||
STB_GLOBAL = 1,
|
||||
STB_WEAK = 2,
|
||||
STB_LOOS = 10,
|
||||
STB_HIOS = 12,
|
||||
STB_LOPROC = 13,
|
||||
STB_HIPROC = 15
|
||||
};
|
||||
|
||||
// Symbol types from Sym st_info field.
|
||||
|
||||
enum STT
|
||||
{
|
||||
STT_NOTYPE = 0,
|
||||
STT_OBJECT = 1,
|
||||
STT_FUNC = 2,
|
||||
STT_SECTION = 3,
|
||||
STT_FILE = 4,
|
||||
STT_COMMON = 5,
|
||||
STT_TLS = 6,
|
||||
STT_LOOS = 10,
|
||||
STT_HIOS = 12,
|
||||
STT_LOPROC = 13,
|
||||
STT_HIPROC = 15
|
||||
};
|
||||
|
||||
// Symbol visibility from Sym st_other field.
|
||||
|
||||
enum STV
|
||||
{
|
||||
STV_DEFAULT = 0,
|
||||
STV_INTERNAL = 1,
|
||||
STV_HIDDEN = 2,
|
||||
STV_PROTECTED = 3
|
||||
};
|
||||
|
||||
} // End namespace elfcpp.
|
||||
|
||||
// Include internal details after defining the types.
|
||||
#include "elfcpp_internal.h"
|
||||
|
||||
namespace elfcpp
|
||||
{
|
||||
|
||||
// The offset of the ELF file header in the ELF file.
|
||||
|
||||
const int file_header_offset = 0;
|
||||
|
||||
// ELF structure sizes.
|
||||
|
||||
template<int size>
|
||||
struct Elf_sizes
|
||||
{
|
||||
// Size of ELF file header.
|
||||
static const int ehdr_size = sizeof(internal::Ehdr_data<size>);
|
||||
// Size of ELF section header.
|
||||
static const int shdr_size = sizeof(internal::Shdr_data<size>);
|
||||
// Size of ELF symbol table entry.
|
||||
static const int sym_size = sizeof(internal::Sym_data<size>);
|
||||
};
|
||||
|
||||
// Accessor class for the ELF file header.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
class Ehdr
|
||||
{
|
||||
public:
|
||||
Ehdr(const unsigned char* p)
|
||||
: p_(reinterpret_cast<const internal::Ehdr_data<size>*>(p))
|
||||
{ }
|
||||
|
||||
const unsigned char*
|
||||
get_e_ident() const
|
||||
{ return this->p_->e_ident; }
|
||||
|
||||
Elf_Half
|
||||
get_e_type() const
|
||||
{ return internal::convert_half<big_endian>(this->p_->e_type); }
|
||||
|
||||
Elf_Half
|
||||
get_e_machine() const
|
||||
{ return internal::convert_half<big_endian>(this->p_->e_machine); }
|
||||
|
||||
Elf_Word
|
||||
get_e_version() const
|
||||
{ return internal::convert_word<big_endian>(this->p_->e_version); }
|
||||
|
||||
typename Elf_types<size>::Elf_Addr
|
||||
get_e_entry() const
|
||||
{ return internal::convert_addr<size, big_endian>(this->p_->e_entry); }
|
||||
|
||||
typename Elf_types<size>::Elf_Off
|
||||
get_e_phoff() const
|
||||
{ return internal::convert_off<size, big_endian>(this->p_->e_phoff); }
|
||||
|
||||
typename Elf_types<size>::Elf_Off
|
||||
get_e_shoff() const
|
||||
{ return internal::convert_off<size, big_endian>(this->p_->e_shoff); }
|
||||
|
||||
Elf_Word
|
||||
get_e_flags() const
|
||||
{ return internal::convert_word<big_endian>(this->p_->e_flags); }
|
||||
|
||||
Elf_Half
|
||||
get_e_ehsize() const
|
||||
{ return internal::convert_half<big_endian>(this->p_->e_ehsize); }
|
||||
|
||||
Elf_Half
|
||||
get_e_phentsize() const
|
||||
{ return internal::convert_half<big_endian>(this->p_->e_phentsize); }
|
||||
|
||||
Elf_Half
|
||||
get_e_phnum() const
|
||||
{ return internal::convert_half<big_endian>(this->p_->e_phnum); }
|
||||
|
||||
Elf_Half
|
||||
get_e_shentsize() const
|
||||
{ return internal::convert_half<big_endian>(this->p_->e_shentsize); }
|
||||
|
||||
Elf_Half
|
||||
get_e_shnum() const
|
||||
{ return internal::convert_half<big_endian>(this->p_->e_shnum); }
|
||||
|
||||
Elf_Half
|
||||
get_e_shstrndx() const
|
||||
{ return internal::convert_half<big_endian>(this->p_->e_shstrndx); }
|
||||
|
||||
private:
|
||||
const internal::Ehdr_data<size>* p_;
|
||||
};
|
||||
|
||||
// Accessor class for an ELF section header.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
class Shdr
|
||||
{
|
||||
public:
|
||||
Shdr(const unsigned char* p)
|
||||
: p_(reinterpret_cast<const internal::Shdr_data<size>*>(p))
|
||||
{ }
|
||||
|
||||
Elf_Word
|
||||
get_sh_name() const
|
||||
{ return internal::convert_word<big_endian>(this->p_->sh_name); }
|
||||
|
||||
Elf_Word
|
||||
get_sh_type() const
|
||||
{ return internal::convert_word<big_endian>(this->p_->sh_type); }
|
||||
|
||||
typename Elf_types<size>::Elf_WXword
|
||||
get_sh_flags() const
|
||||
{ return internal::convert_wxword<size, big_endian>(this->p_->sh_flags); }
|
||||
|
||||
typename Elf_types<size>::Elf_Addr
|
||||
get_sh_addr() const
|
||||
{ return internal::convert_addr<size, big_endian>(this->p_->sh_addr); }
|
||||
|
||||
typename Elf_types<size>::Elf_Off
|
||||
get_sh_offset() const
|
||||
{ return internal::convert_off<size, big_endian>(this->p_->sh_offset); }
|
||||
|
||||
typename Elf_types<size>::Elf_WXword
|
||||
get_sh_size() const
|
||||
{ return internal::convert_wxword<size, big_endian>(this->p_->sh_size); }
|
||||
|
||||
Elf_Word
|
||||
get_sh_link() const
|
||||
{ return internal::convert_word<big_endian>(this->p_->sh_link); }
|
||||
|
||||
Elf_Word
|
||||
get_sh_info() const
|
||||
{ return internal::convert_word<big_endian>(this->p_->sh_info); }
|
||||
|
||||
typename Elf_types<size>::Elf_WXword
|
||||
get_sh_addralign() const
|
||||
{ return
|
||||
internal::convert_wxword<size, big_endian>(this->p_->sh_addralign); }
|
||||
|
||||
typename Elf_types<size>::Elf_WXword
|
||||
get_sh_entsize() const
|
||||
{ return internal::convert_wxword<size, big_endian>(this->p_->sh_entsize); }
|
||||
|
||||
private:
|
||||
const internal::Shdr_data<size>* p_;
|
||||
};
|
||||
|
||||
// Accessor class for an ELF symbol table entry.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
class Sym
|
||||
{
|
||||
public:
|
||||
Sym(const unsigned char* p)
|
||||
: p_(reinterpret_cast<const internal::Sym_data<size>*>(p))
|
||||
{ }
|
||||
|
||||
Elf_Word
|
||||
get_st_name() const
|
||||
{ return internal::convert_word<big_endian>(this->p_->st_name); }
|
||||
|
||||
typename Elf_types<size>::Elf_Addr
|
||||
get_st_value() const
|
||||
{ return internal::convert_addr<size, big_endian>(this->p_->st_value); }
|
||||
|
||||
typename Elf_types<size>::Elf_WXword
|
||||
get_st_size() const
|
||||
{ return internal::convert_wxword<big_endian>(this->p_->st_size); }
|
||||
|
||||
unsigned char
|
||||
get_st_info() const
|
||||
{ return this->p_->st_info; }
|
||||
|
||||
unsigned char
|
||||
get_st_other() const
|
||||
{ return this->p_->st_other; }
|
||||
|
||||
Elf_Half
|
||||
get_st_shndx() const
|
||||
{ return internal::convert_half<big_endian>(this->p_->st_shndx); }
|
||||
|
||||
private:
|
||||
const internal::Sym_data<size>* p_;
|
||||
};
|
||||
|
||||
} // End namespace elfcpp.
|
||||
|
||||
#endif // !defined(ELFPCP_H)
|
|
@ -0,0 +1,238 @@
|
|||
// elfcpp_internal.h -- internals for elfcpp -*- C++ -*-
|
||||
|
||||
// This is included by elfcpp.h, the external interface, but holds
|
||||
// information which we want to keep private.
|
||||
|
||||
#include "elfcpp_config.h"
|
||||
|
||||
#include <byteswap.h>
|
||||
|
||||
#ifndef ELFCPP_INTERNAL_H
|
||||
#define ELFCPP_INTERNAL_H
|
||||
|
||||
namespace elfcpp
|
||||
{
|
||||
|
||||
namespace internal
|
||||
{
|
||||
|
||||
#ifdef WORDS_BIG_ENDIAN
|
||||
const bool host_big_endian = true;
|
||||
#else
|
||||
const bool host_big_endian = false;
|
||||
#endif
|
||||
|
||||
// Conversion routines between target and host.
|
||||
|
||||
// Convert Elf_Half.
|
||||
|
||||
template<bool same_endian>
|
||||
Elf_Half
|
||||
convert_half_host(Elf_Half v);
|
||||
|
||||
template<>
|
||||
inline Elf_Half
|
||||
convert_half_host<true>(Elf_Half v)
|
||||
{
|
||||
return v;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline Elf_Half
|
||||
convert_half_host<false>(Elf_Half v)
|
||||
{
|
||||
return bswap_16(v);
|
||||
}
|
||||
|
||||
template<bool big_endian>
|
||||
inline Elf_Half
|
||||
convert_half(Elf_Half v)
|
||||
{
|
||||
return convert_half_host<big_endian == host_big_endian>(v);
|
||||
}
|
||||
|
||||
// Convert Elf_Word.
|
||||
|
||||
template<bool same_endian>
|
||||
Elf_Word
|
||||
convert_word_host(Elf_Word v);
|
||||
|
||||
template<>
|
||||
inline Elf_Word
|
||||
convert_word_host<true>(Elf_Word v)
|
||||
{
|
||||
return v;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline Elf_Word
|
||||
convert_word_host<false>(Elf_Word v)
|
||||
{
|
||||
return bswap_32(v);
|
||||
}
|
||||
|
||||
template<bool big_endian>
|
||||
inline Elf_Word
|
||||
convert_word(Elf_Word v)
|
||||
{
|
||||
return convert_word_host<big_endian == host_big_endian>(v);
|
||||
}
|
||||
|
||||
// Convert Elf_Xword.
|
||||
|
||||
template<bool same_endian>
|
||||
Elf_Xword
|
||||
convert_xword_host(Elf_Xword v);
|
||||
|
||||
template<>
|
||||
inline Elf_Xword
|
||||
convert_xword_host<true>(Elf_Xword v)
|
||||
{
|
||||
return v;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline Elf_Xword
|
||||
convert_xword_host<false>(Elf_Xword v)
|
||||
{
|
||||
return bswap_64(v);
|
||||
}
|
||||
|
||||
template<bool big_endian>
|
||||
inline Elf_Xword
|
||||
convert_xword(Elf_Xword v)
|
||||
{
|
||||
return convert_xword_host<big_endian == host_big_endian>(v);
|
||||
}
|
||||
|
||||
// Convert Elf_addr.
|
||||
|
||||
template<int size, bool same_endian>
|
||||
typename Elf_types<size>::Elf_Addr
|
||||
convert_addr_size(typename Elf_types<size>::Elf_Addr);
|
||||
|
||||
template<>
|
||||
inline Elf_types<32>::Elf_Addr
|
||||
convert_addr_size<32, true>(Elf_types<32>::Elf_Addr v)
|
||||
{
|
||||
return v;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline Elf_types<64>::Elf_Addr
|
||||
convert_addr_size<64, true>(Elf_types<64>::Elf_Addr v)
|
||||
{
|
||||
return v;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline Elf_types<32>::Elf_Addr
|
||||
convert_addr_size<32, false>(Elf_types<32>::Elf_Addr v)
|
||||
{
|
||||
return bswap_32(v);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline Elf_types<64>::Elf_Addr
|
||||
convert_addr_size<64, false>(Elf_types<64>::Elf_Addr v)
|
||||
{
|
||||
return bswap_64(v);
|
||||
}
|
||||
|
||||
template<int size, bool big_endian>
|
||||
inline typename Elf_types<size>::Elf_Addr
|
||||
convert_addr(typename Elf_types<size>::Elf_Addr v)
|
||||
{
|
||||
return convert_addr_size<size, big_endian == host_big_endian>(v);
|
||||
}
|
||||
|
||||
// Convert Elf_Off.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
inline typename Elf_types<size>::Elf_Off
|
||||
convert_off(typename Elf_types<size>::Elf_Off v)
|
||||
{
|
||||
return convert_addr_size<size, big_endian == host_big_endian>(v);
|
||||
}
|
||||
|
||||
// Convert Elf_WXword.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
inline typename Elf_types<size>::Elf_Off
|
||||
convert_wxword(typename Elf_types<size>::Elf_Off v)
|
||||
{
|
||||
return convert_addr_size<size, big_endian == host_big_endian>(v);
|
||||
}
|
||||
|
||||
// The ELF file header.
|
||||
|
||||
template<int size>
|
||||
struct Ehdr_data
|
||||
{
|
||||
unsigned char e_ident[EI_NIDENT];
|
||||
Elf_Half e_type;
|
||||
Elf_Half e_machine;
|
||||
Elf_Word e_version;
|
||||
typename Elf_types<size>::Elf_Addr e_entry;
|
||||
typename Elf_types<size>::Elf_Off e_phoff;
|
||||
typename Elf_types<size>::Elf_Off e_shoff;
|
||||
Elf_Word e_flags;
|
||||
Elf_Half e_ehsize;
|
||||
Elf_Half e_phentsize;
|
||||
Elf_Half e_phnum;
|
||||
Elf_Half e_shentsize;
|
||||
Elf_Half e_shnum;
|
||||
Elf_Half e_shstrndx;
|
||||
};
|
||||
|
||||
// An Elf section header.
|
||||
|
||||
template<int size>
|
||||
struct Shdr_data
|
||||
{
|
||||
Elf_Word sh_name;
|
||||
Elf_Word sh_type;
|
||||
typename Elf_types<size>::Elf_WXword sh_flags;
|
||||
typename Elf_types<size>::Elf_Addr sh_addr;
|
||||
typename Elf_types<size>::Elf_Off sh_offset;
|
||||
typename Elf_types<size>::Elf_WXword sh_size;
|
||||
Elf_Word sh_link;
|
||||
Elf_Word sh_info;
|
||||
typename Elf_types<size>::Elf_WXword sh_addralign;
|
||||
typename Elf_types<size>::Elf_WXword sh_entsize;
|
||||
};
|
||||
|
||||
// An ELF symbol table entry. We use template specialization for the
|
||||
// 32-bit and 64-bit versions because the fields are in a different
|
||||
// order.
|
||||
|
||||
template<int size>
|
||||
struct Sym_data;
|
||||
|
||||
template<>
|
||||
struct Sym_data<32>
|
||||
{
|
||||
Elf_Word st_name;
|
||||
Elf_types<32>::Elf_Addr st_value;
|
||||
Elf_Word st_size;
|
||||
unsigned char st_info;
|
||||
unsigned char st_other;
|
||||
Elf_Half st_shndx;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Sym_data<64>
|
||||
{
|
||||
Elf_Word st_name;
|
||||
unsigned char st_info;
|
||||
unsigned char st_other;
|
||||
Elf_Half st_shndx;
|
||||
Elf_types<64>::Elf_Addr st_value;
|
||||
Elf_Xword st_size;
|
||||
};
|
||||
|
||||
} // End namespace internal.
|
||||
|
||||
} // End namespace elfcpp.
|
||||
|
||||
#endif // !defined(ELFCPP_INTERNAL_H)
|
|
@ -0,0 +1,69 @@
|
|||
# Process this file with automake to generate Makefile.in
|
||||
|
||||
AUTOMAKE_OPTIONS =
|
||||
|
||||
SUBDIRS = po
|
||||
|
||||
tooldir = $(exec_prefix)/$(target_alias)
|
||||
|
||||
ACLOCAL_AMFLAGS = -I ../bfd -I ../config
|
||||
|
||||
AM_CXXFLAGS = $(WARN_CXXFLAGS) $(LFS_CXXFLAGS)
|
||||
|
||||
INCLUDES = -D_GNU_SOURCE \
|
||||
-I$(srcdir) -I$(srcdir)/../include -I$(srcdir)/../elfcpp \
|
||||
-DLOCALEDIR="\"$(datadir)/locale\"" \
|
||||
@INCINTL@
|
||||
|
||||
noinst_PROGRAMS = ld-new
|
||||
|
||||
CFILES = \
|
||||
dirsearch.cc \
|
||||
fileread.cc \
|
||||
gold.cc \
|
||||
gold-threads.cc \
|
||||
object.cc \
|
||||
options.cc \
|
||||
readsyms.cc \
|
||||
workqueue.cc
|
||||
|
||||
HFILES = \
|
||||
dirsearch.h \
|
||||
fileread.h \
|
||||
gold.h \
|
||||
gold-threads.h \
|
||||
object.h \
|
||||
options.h \
|
||||
readsyms.h \
|
||||
symtab.h \
|
||||
target.h \
|
||||
targetsize.h \
|
||||
workqueue.h
|
||||
|
||||
OFILES = gold.o options.o
|
||||
|
||||
POTFILES= $(CFILES) $(HFILES)
|
||||
|
||||
po/POTFILES.in: @MAINT@ Makefile
|
||||
for f in $(POTFILES); do echo $$f; done | LC_COLLATE= sort > tmp \
|
||||
&& mv tmp $(srcdir)/po/POTFILES.in
|
||||
|
||||
ld_new_SOURCES = $(CFILES) $(HFILES)
|
||||
ld_new_DEPENDENCIES = $(LIBINTL_DEP)
|
||||
ld_new_LDADD = $(LIBINTL)
|
||||
|
||||
.PHONY: install-exec-local
|
||||
|
||||
install-exec-local: ld-new$(EXEEXT)
|
||||
$(mkinstalldirs) $(DESTDIR)$(bindir) $(DESTDIR)$(tooldir)/bin
|
||||
n=`echo ld | sed '$(transform)'; \
|
||||
$(INSTALL_PROGRAM) ld-new$(EXEEXT) $(DESTDIR)$(bindir)/$${n}$(EXEEXT); \
|
||||
if test "$(bindir)" != "$(tooldir)/bin"; then \
|
||||
rm -f $(DESTDIR)$(tooldir)/bin/ld$(EXEEXT); \
|
||||
ln $(DESTDIR)$(bindir)/$${n}$(EXEEXT) $(DESTDIR)$(tooldir)/bin/ld$(EXEEXT) >/dev/null 2>/dev/null \
|
||||
|| $(INSTALL_PROGRAM) ld-new$(EXEEXT) $(DESTDIR)$(tooldir)/bin/ld$(EXEEXT); \
|
||||
fi
|
||||
|
||||
# We want install to imply install-info as per GNU standards, despite
|
||||
# the cygnus option.
|
||||
install-data-local: install-info
|
|
@ -0,0 +1,745 @@
|
|||
# Makefile.in generated by automake 1.9.5 from Makefile.am.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
|
||||
# 2003, 2004, 2005 Free Software Foundation, Inc.
|
||||
# This Makefile.in is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
@SET_MAKE@
|
||||
|
||||
# Process this file with automake to generate Makefile.in
|
||||
|
||||
SOURCES = $(ld_new_SOURCES)
|
||||
|
||||
srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
VPATH = @srcdir@
|
||||
pkgdatadir = $(datadir)/@PACKAGE@
|
||||
pkglibdir = $(libdir)/@PACKAGE@
|
||||
pkgincludedir = $(includedir)/@PACKAGE@
|
||||
top_builddir = .
|
||||
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
|
||||
INSTALL = @INSTALL@
|
||||
install_sh_DATA = $(install_sh) -c -m 644
|
||||
install_sh_PROGRAM = $(install_sh) -c
|
||||
install_sh_SCRIPT = $(install_sh) -c
|
||||
INSTALL_HEADER = $(INSTALL_DATA)
|
||||
transform = $(program_transform_name)
|
||||
NORMAL_INSTALL = :
|
||||
PRE_INSTALL = :
|
||||
POST_INSTALL = :
|
||||
NORMAL_UNINSTALL = :
|
||||
PRE_UNINSTALL = :
|
||||
POST_UNINSTALL = :
|
||||
build_triplet = @build@
|
||||
host_triplet = @host@
|
||||
target_triplet = @target@
|
||||
noinst_PROGRAMS = ld-new$(EXEEXT)
|
||||
DIST_COMMON = README $(am__configure_deps) $(srcdir)/../config.guess \
|
||||
$(srcdir)/../config.sub $(srcdir)/../depcomp \
|
||||
$(srcdir)/../install-sh $(srcdir)/../missing \
|
||||
$(srcdir)/../mkinstalldirs $(srcdir)/Makefile.am \
|
||||
$(srcdir)/Makefile.in $(srcdir)/config.in \
|
||||
$(top_srcdir)/configure $(top_srcdir)/po/Make-in
|
||||
subdir = .
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/../config/depstand.m4 \
|
||||
$(top_srcdir)/../config/lead-dot.m4 \
|
||||
$(top_srcdir)/../bfd/../config/progtest.m4 \
|
||||
$(top_srcdir)/../bfd/../config/po.m4 \
|
||||
$(top_srcdir)/../bfd/../config/nls.m4 \
|
||||
$(top_srcdir)/../bfd/../config/gettext-sister.m4 \
|
||||
$(top_srcdir)/../bfd/warning.m4 $(top_srcdir)/configure.ac
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
|
||||
configure.lineno configure.status.lineno
|
||||
mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs
|
||||
CONFIG_HEADER = config.h
|
||||
CONFIG_CLEAN_FILES = po/Makefile.in
|
||||
PROGRAMS = $(noinst_PROGRAMS)
|
||||
am__objects_1 = dirsearch.$(OBJEXT) fileread.$(OBJEXT) gold.$(OBJEXT) \
|
||||
gold-threads.$(OBJEXT) object.$(OBJEXT) options.$(OBJEXT) \
|
||||
readsyms.$(OBJEXT) workqueue.$(OBJEXT)
|
||||
am__objects_2 =
|
||||
am_ld_new_OBJECTS = $(am__objects_1) $(am__objects_2)
|
||||
ld_new_OBJECTS = $(am_ld_new_OBJECTS)
|
||||
am__DEPENDENCIES_1 =
|
||||
DEFAULT_INCLUDES = -I. -I$(srcdir) -I.
|
||||
depcomp = $(SHELL) $(top_srcdir)/../depcomp
|
||||
am__depfiles_maybe = depfiles
|
||||
CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
|
||||
$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
|
||||
CXXLD = $(CXX)
|
||||
CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \
|
||||
-o $@
|
||||
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
|
||||
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
|
||||
CCLD = $(CC)
|
||||
LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
|
||||
SOURCES = $(ld_new_SOURCES)
|
||||
DIST_SOURCES = $(ld_new_SOURCES)
|
||||
RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
|
||||
html-recursive info-recursive install-data-recursive \
|
||||
install-exec-recursive install-info-recursive \
|
||||
install-recursive installcheck-recursive installdirs-recursive \
|
||||
pdf-recursive ps-recursive uninstall-info-recursive \
|
||||
uninstall-recursive
|
||||
ETAGS = etags
|
||||
CTAGS = ctags
|
||||
DIST_SUBDIRS = $(SUBDIRS)
|
||||
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
||||
distdir = $(PACKAGE)-$(VERSION)
|
||||
top_distdir = $(distdir)
|
||||
am__remove_distdir = \
|
||||
{ test ! -d $(distdir) \
|
||||
|| { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \
|
||||
&& rm -fr $(distdir); }; }
|
||||
DIST_ARCHIVES = $(distdir).tar.gz
|
||||
GZIP_ENV = --best
|
||||
distuninstallcheck_listfiles = find . -type f -print
|
||||
distcleancheck_listfiles = find . -type f -print
|
||||
ACLOCAL = @ACLOCAL@
|
||||
AMDEP_FALSE = @AMDEP_FALSE@
|
||||
AMDEP_TRUE = @AMDEP_TRUE@
|
||||
AMTAR = @AMTAR@
|
||||
AUTOCONF = @AUTOCONF@
|
||||
AUTOHEADER = @AUTOHEADER@
|
||||
AUTOMAKE = @AUTOMAKE@
|
||||
AWK = @AWK@
|
||||
CATALOGS = @CATALOGS@
|
||||
CATOBJEXT = @CATOBJEXT@
|
||||
CC = @CC@
|
||||
CCDEPMODE = @CCDEPMODE@
|
||||
CFLAGS = @CFLAGS@
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
CXX = @CXX@
|
||||
CXXDEPMODE = @CXXDEPMODE@
|
||||
CXXFLAGS = @CXXFLAGS@
|
||||
CYGPATH_W = @CYGPATH_W@
|
||||
DATADIRNAME = @DATADIRNAME@
|
||||
DEFS = @DEFS@
|
||||
DEPDIR = @DEPDIR@
|
||||
ECHO_C = @ECHO_C@
|
||||
ECHO_N = @ECHO_N@
|
||||
ECHO_T = @ECHO_T@
|
||||
EXEEXT = @EXEEXT@
|
||||
GENCAT = @GENCAT@
|
||||
GMSGFMT = @GMSGFMT@
|
||||
INCINTL = @INCINTL@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
||||
INSTOBJEXT = @INSTOBJEXT@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LFS_CXXFLAGS = @LFS_CXXFLAGS@
|
||||
LIBINTL = @LIBINTL@
|
||||
LIBINTL_DEP = @LIBINTL_DEP@
|
||||
LIBOBJS = @LIBOBJS@
|
||||
LIBS = @LIBS@
|
||||
LTLIBOBJS = @LTLIBOBJS@
|
||||
MAINT = @MAINT@
|
||||
MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
|
||||
MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
|
||||
MAKEINFO = @MAKEINFO@
|
||||
MKINSTALLDIRS = @MKINSTALLDIRS@
|
||||
MSGFMT = @MSGFMT@
|
||||
MSGMERGE = @MSGMERGE@
|
||||
NO_WERROR = @NO_WERROR@
|
||||
OBJEXT = @OBJEXT@
|
||||
PACKAGE = @PACKAGE@
|
||||
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
|
||||
PACKAGE_NAME = @PACKAGE_NAME@
|
||||
PACKAGE_STRING = @PACKAGE_STRING@
|
||||
PACKAGE_TARNAME = @PACKAGE_TARNAME@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
PATH_SEPARATOR = @PATH_SEPARATOR@
|
||||
POSUB = @POSUB@
|
||||
SET_MAKE = @SET_MAKE@
|
||||
SHELL = @SHELL@
|
||||
STRIP = @STRIP@
|
||||
USE_NLS = @USE_NLS@
|
||||
VERSION = @VERSION@
|
||||
WARN_CFLAGS = @WARN_CFLAGS@
|
||||
WARN_CXXFLAGS = @WARN_CXXFLAGS@
|
||||
XGETTEXT = @XGETTEXT@
|
||||
ac_ct_CC = @ac_ct_CC@
|
||||
ac_ct_CXX = @ac_ct_CXX@
|
||||
ac_ct_STRIP = @ac_ct_STRIP@
|
||||
am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
|
||||
am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
|
||||
am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
|
||||
am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
|
||||
am__include = @am__include@
|
||||
am__leading_dot = @am__leading_dot@
|
||||
am__quote = @am__quote@
|
||||
am__tar = @am__tar@
|
||||
am__untar = @am__untar@
|
||||
bindir = @bindir@
|
||||
build = @build@
|
||||
build_alias = @build_alias@
|
||||
build_cpu = @build_cpu@
|
||||
build_os = @build_os@
|
||||
build_vendor = @build_vendor@
|
||||
datadir = @datadir@
|
||||
exec_prefix = @exec_prefix@
|
||||
host = @host@
|
||||
host_alias = @host_alias@
|
||||
host_cpu = @host_cpu@
|
||||
host_os = @host_os@
|
||||
host_vendor = @host_vendor@
|
||||
includedir = @includedir@
|
||||
infodir = @infodir@
|
||||
install_sh = @install_sh@
|
||||
libdir = @libdir@
|
||||
libexecdir = @libexecdir@
|
||||
localstatedir = @localstatedir@
|
||||
mandir = @mandir@
|
||||
mkdir_p = @mkdir_p@
|
||||
oldincludedir = @oldincludedir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
sysconfdir = @sysconfdir@
|
||||
target = @target@
|
||||
target_alias = @target_alias@
|
||||
target_cpu = @target_cpu@
|
||||
target_os = @target_os@
|
||||
target_vendor = @target_vendor@
|
||||
AUTOMAKE_OPTIONS =
|
||||
SUBDIRS = po
|
||||
tooldir = $(exec_prefix)/$(target_alias)
|
||||
ACLOCAL_AMFLAGS = -I ../bfd -I ../config
|
||||
AM_CXXFLAGS = $(WARN_CXXFLAGS) $(LFS_CXXFLAGS)
|
||||
INCLUDES = -D_GNU_SOURCE \
|
||||
-I$(srcdir) -I$(srcdir)/../include -I$(srcdir)/../elfcpp \
|
||||
-DLOCALEDIR="\"$(datadir)/locale\"" \
|
||||
@INCINTL@
|
||||
|
||||
CFILES = \
|
||||
dirsearch.cc \
|
||||
fileread.cc \
|
||||
gold.cc \
|
||||
gold-threads.cc \
|
||||
object.cc \
|
||||
options.cc \
|
||||
readsyms.cc \
|
||||
workqueue.cc
|
||||
|
||||
HFILES = \
|
||||
dirsearch.h \
|
||||
fileread.h \
|
||||
gold.h \
|
||||
gold-threads.h \
|
||||
object.h \
|
||||
options.h \
|
||||
readsyms.h \
|
||||
symtab.h \
|
||||
target.h \
|
||||
targetsize.h \
|
||||
workqueue.h
|
||||
|
||||
OFILES = gold.o options.o
|
||||
POTFILES = $(CFILES) $(HFILES)
|
||||
ld_new_SOURCES = $(CFILES) $(HFILES)
|
||||
ld_new_DEPENDENCIES = $(LIBINTL_DEP)
|
||||
ld_new_LDADD = $(LIBINTL)
|
||||
all: config.h
|
||||
$(MAKE) $(AM_MAKEFLAGS) all-recursive
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .cc .o .obj
|
||||
am--refresh:
|
||||
@:
|
||||
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
|
||||
@for dep in $?; do \
|
||||
case '$(am__configure_deps)' in \
|
||||
*$$dep*) \
|
||||
echo ' cd $(srcdir) && $(AUTOMAKE) --foreign '; \
|
||||
cd $(srcdir) && $(AUTOMAKE) --foreign \
|
||||
&& exit 0; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
done; \
|
||||
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \
|
||||
cd $(top_srcdir) && \
|
||||
$(AUTOMAKE) --foreign Makefile
|
||||
.PRECIOUS: Makefile
|
||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||
@case '$?' in \
|
||||
*config.status*) \
|
||||
echo ' $(SHELL) ./config.status'; \
|
||||
$(SHELL) ./config.status;; \
|
||||
*) \
|
||||
echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
|
||||
esac;
|
||||
|
||||
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
|
||||
$(SHELL) ./config.status --recheck
|
||||
|
||||
$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
|
||||
cd $(srcdir) && $(AUTOCONF)
|
||||
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
|
||||
cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
|
||||
|
||||
config.h: stamp-h1
|
||||
@if test ! -f $@; then \
|
||||
rm -f stamp-h1; \
|
||||
$(MAKE) stamp-h1; \
|
||||
else :; fi
|
||||
|
||||
stamp-h1: $(srcdir)/config.in $(top_builddir)/config.status
|
||||
@rm -f stamp-h1
|
||||
cd $(top_builddir) && $(SHELL) ./config.status config.h
|
||||
$(srcdir)/config.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
|
||||
cd $(top_srcdir) && $(AUTOHEADER)
|
||||
rm -f stamp-h1
|
||||
touch $@
|
||||
|
||||
distclean-hdr:
|
||||
-rm -f config.h stamp-h1
|
||||
po/Makefile.in: $(top_builddir)/config.status $(top_srcdir)/po/Make-in
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $@
|
||||
|
||||
clean-noinstPROGRAMS:
|
||||
-test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS)
|
||||
ld-new$(EXEEXT): $(ld_new_OBJECTS) $(ld_new_DEPENDENCIES)
|
||||
@rm -f ld-new$(EXEEXT)
|
||||
$(CXXLINK) $(ld_new_LDFLAGS) $(ld_new_OBJECTS) $(ld_new_LDADD) $(LIBS)
|
||||
|
||||
mostlyclean-compile:
|
||||
-rm -f *.$(OBJEXT)
|
||||
|
||||
distclean-compile:
|
||||
-rm -f *.tab.c
|
||||
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dirsearch.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fileread.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gold-threads.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gold.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/object.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/options.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/readsyms.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/workqueue.Po@am__quote@
|
||||
|
||||
.cc.o:
|
||||
@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $<
|
||||
|
||||
.cc.obj:
|
||||
@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
|
||||
uninstall-info-am:
|
||||
|
||||
# This directory's subdirectories are mostly independent; you can cd
|
||||
# into them and run `make' without going through this Makefile.
|
||||
# To change the values of `make' variables: instead of editing Makefiles,
|
||||
# (1) if the variable is set in `config.status', edit `config.status'
|
||||
# (which will cause the Makefiles to be regenerated when you run `make');
|
||||
# (2) otherwise, pass the desired values on the `make' command line.
|
||||
$(RECURSIVE_TARGETS):
|
||||
@failcom='exit 1'; \
|
||||
for f in x $$MAKEFLAGS; do \
|
||||
case $$f in \
|
||||
*=* | --[!k]*);; \
|
||||
*k*) failcom='fail=yes';; \
|
||||
esac; \
|
||||
done; \
|
||||
dot_seen=no; \
|
||||
target=`echo $@ | sed s/-recursive//`; \
|
||||
list='$(SUBDIRS)'; for subdir in $$list; do \
|
||||
echo "Making $$target in $$subdir"; \
|
||||
if test "$$subdir" = "."; then \
|
||||
dot_seen=yes; \
|
||||
local_target="$$target-am"; \
|
||||
else \
|
||||
local_target="$$target"; \
|
||||
fi; \
|
||||
(cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
|
||||
|| eval $$failcom; \
|
||||
done; \
|
||||
if test "$$dot_seen" = "no"; then \
|
||||
$(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
|
||||
fi; test -z "$$fail"
|
||||
|
||||
mostlyclean-recursive clean-recursive distclean-recursive \
|
||||
maintainer-clean-recursive:
|
||||
@failcom='exit 1'; \
|
||||
for f in x $$MAKEFLAGS; do \
|
||||
case $$f in \
|
||||
*=* | --[!k]*);; \
|
||||
*k*) failcom='fail=yes';; \
|
||||
esac; \
|
||||
done; \
|
||||
dot_seen=no; \
|
||||
case "$@" in \
|
||||
distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
|
||||
*) list='$(SUBDIRS)' ;; \
|
||||
esac; \
|
||||
rev=''; for subdir in $$list; do \
|
||||
if test "$$subdir" = "."; then :; else \
|
||||
rev="$$subdir $$rev"; \
|
||||
fi; \
|
||||
done; \
|
||||
rev="$$rev ."; \
|
||||
target=`echo $@ | sed s/-recursive//`; \
|
||||
for subdir in $$rev; do \
|
||||
echo "Making $$target in $$subdir"; \
|
||||
if test "$$subdir" = "."; then \
|
||||
local_target="$$target-am"; \
|
||||
else \
|
||||
local_target="$$target"; \
|
||||
fi; \
|
||||
(cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
|
||||
|| eval $$failcom; \
|
||||
done && test -z "$$fail"
|
||||
tags-recursive:
|
||||
list='$(SUBDIRS)'; for subdir in $$list; do \
|
||||
test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
|
||||
done
|
||||
ctags-recursive:
|
||||
list='$(SUBDIRS)'; for subdir in $$list; do \
|
||||
test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
|
||||
done
|
||||
|
||||
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) ' { files[$$0] = 1; } \
|
||||
END { for (i in files) print i; }'`; \
|
||||
mkid -fID $$unique
|
||||
tags: TAGS
|
||||
|
||||
TAGS: tags-recursive $(HEADERS) $(SOURCES) config.in $(TAGS_DEPENDENCIES) \
|
||||
$(TAGS_FILES) $(LISP)
|
||||
tags=; \
|
||||
here=`pwd`; \
|
||||
if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
|
||||
include_option=--etags-include; \
|
||||
empty_fix=.; \
|
||||
else \
|
||||
include_option=--include; \
|
||||
empty_fix=; \
|
||||
fi; \
|
||||
list='$(SUBDIRS)'; for subdir in $$list; do \
|
||||
if test "$$subdir" = .; then :; else \
|
||||
test ! -f $$subdir/TAGS || \
|
||||
tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \
|
||||
fi; \
|
||||
done; \
|
||||
list='$(SOURCES) $(HEADERS) config.in $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) ' { files[$$0] = 1; } \
|
||||
END { for (i in files) print i; }'`; \
|
||||
if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
|
||||
test -n "$$unique" || unique=$$empty_fix; \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
$$tags $$unique; \
|
||||
fi
|
||||
ctags: CTAGS
|
||||
CTAGS: ctags-recursive $(HEADERS) $(SOURCES) config.in $(TAGS_DEPENDENCIES) \
|
||||
$(TAGS_FILES) $(LISP)
|
||||
tags=; \
|
||||
here=`pwd`; \
|
||||
list='$(SOURCES) $(HEADERS) config.in $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) ' { files[$$0] = 1; } \
|
||||
END { for (i in files) print i; }'`; \
|
||||
test -z "$(CTAGS_ARGS)$$tags$$unique" \
|
||||
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
|
||||
$$tags $$unique
|
||||
|
||||
GTAGS:
|
||||
here=`$(am__cd) $(top_builddir) && pwd` \
|
||||
&& cd $(top_srcdir) \
|
||||
&& gtags -i $(GTAGS_ARGS) $$here
|
||||
|
||||
distclean-tags:
|
||||
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
|
||||
|
||||
distdir: $(DISTFILES)
|
||||
$(am__remove_distdir)
|
||||
mkdir $(distdir)
|
||||
$(mkdir_p) $(distdir)/.. $(distdir)/../bfd $(distdir)/../bfd/../config $(distdir)/../config $(distdir)/po
|
||||
@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
|
||||
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
|
||||
list='$(DISTFILES)'; for file in $$list; do \
|
||||
case $$file in \
|
||||
$(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
|
||||
$(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
|
||||
esac; \
|
||||
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
|
||||
dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
|
||||
if test "$$dir" != "$$file" && test "$$dir" != "."; then \
|
||||
dir="/$$dir"; \
|
||||
$(mkdir_p) "$(distdir)$$dir"; \
|
||||
else \
|
||||
dir=''; \
|
||||
fi; \
|
||||
if test -d $$d/$$file; then \
|
||||
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
|
||||
cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
|
||||
fi; \
|
||||
cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
|
||||
else \
|
||||
test -f $(distdir)/$$file \
|
||||
|| cp -p $$d/$$file $(distdir)/$$file \
|
||||
|| exit 1; \
|
||||
fi; \
|
||||
done
|
||||
list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
|
||||
if test "$$subdir" = .; then :; else \
|
||||
test -d "$(distdir)/$$subdir" \
|
||||
|| $(mkdir_p) "$(distdir)/$$subdir" \
|
||||
|| exit 1; \
|
||||
distdir=`$(am__cd) $(distdir) && pwd`; \
|
||||
top_distdir=`$(am__cd) $(top_distdir) && pwd`; \
|
||||
(cd $$subdir && \
|
||||
$(MAKE) $(AM_MAKEFLAGS) \
|
||||
top_distdir="$$top_distdir" \
|
||||
distdir="$$distdir/$$subdir" \
|
||||
distdir) \
|
||||
|| exit 1; \
|
||||
fi; \
|
||||
done
|
||||
-find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \
|
||||
! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
|
||||
! -type d ! -perm -400 -exec chmod a+r {} \; -o \
|
||||
! -type d ! -perm -444 -exec $(SHELL) $(install_sh) -c -m a+r {} {} \; \
|
||||
|| chmod -R a+r $(distdir)
|
||||
dist-gzip: distdir
|
||||
tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
|
||||
$(am__remove_distdir)
|
||||
|
||||
dist-bzip2: distdir
|
||||
tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2
|
||||
$(am__remove_distdir)
|
||||
|
||||
dist-tarZ: distdir
|
||||
tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
|
||||
$(am__remove_distdir)
|
||||
|
||||
dist-shar: distdir
|
||||
shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
|
||||
$(am__remove_distdir)
|
||||
|
||||
dist-zip: distdir
|
||||
-rm -f $(distdir).zip
|
||||
zip -rq $(distdir).zip $(distdir)
|
||||
$(am__remove_distdir)
|
||||
|
||||
dist dist-all: distdir
|
||||
tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
|
||||
$(am__remove_distdir)
|
||||
|
||||
# This target untars the dist file and tries a VPATH configuration. Then
|
||||
# it guarantees that the distribution is self-contained by making another
|
||||
# tarfile.
|
||||
distcheck: dist
|
||||
case '$(DIST_ARCHIVES)' in \
|
||||
*.tar.gz*) \
|
||||
GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\
|
||||
*.tar.bz2*) \
|
||||
bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\
|
||||
*.tar.Z*) \
|
||||
uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
|
||||
*.shar.gz*) \
|
||||
GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\
|
||||
*.zip*) \
|
||||
unzip $(distdir).zip ;;\
|
||||
esac
|
||||
chmod -R a-w $(distdir); chmod a+w $(distdir)
|
||||
mkdir $(distdir)/_build
|
||||
mkdir $(distdir)/_inst
|
||||
chmod a-w $(distdir)
|
||||
dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
|
||||
&& dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
|
||||
&& cd $(distdir)/_build \
|
||||
&& ../configure --srcdir=.. --prefix="$$dc_install_base" \
|
||||
$(DISTCHECK_CONFIGURE_FLAGS) \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) dvi \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) check \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) install \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) installcheck \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) uninstall \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
|
||||
distuninstallcheck \
|
||||
&& chmod -R a-w "$$dc_install_base" \
|
||||
&& ({ \
|
||||
(cd ../.. && umask 077 && mkdir "$$dc_destdir") \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
|
||||
distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
|
||||
} || { rm -rf "$$dc_destdir"; exit 1; }) \
|
||||
&& rm -rf "$$dc_destdir" \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) dist \
|
||||
&& rm -rf $(DIST_ARCHIVES) \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) distcleancheck
|
||||
$(am__remove_distdir)
|
||||
@(echo "$(distdir) archives ready for distribution: "; \
|
||||
list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
|
||||
sed -e '1{h;s/./=/g;p;x;}' -e '$${p;x;}'
|
||||
distuninstallcheck:
|
||||
@cd $(distuninstallcheck_dir) \
|
||||
&& test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \
|
||||
|| { echo "ERROR: files left after uninstall:" ; \
|
||||
if test -n "$(DESTDIR)"; then \
|
||||
echo " (check DESTDIR support)"; \
|
||||
fi ; \
|
||||
$(distuninstallcheck_listfiles) ; \
|
||||
exit 1; } >&2
|
||||
distcleancheck: distclean
|
||||
@if test '$(srcdir)' = . ; then \
|
||||
echo "ERROR: distcleancheck can only run from a VPATH build" ; \
|
||||
exit 1 ; \
|
||||
fi
|
||||
@test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
|
||||
|| { echo "ERROR: files left in build directory after distclean:" ; \
|
||||
$(distcleancheck_listfiles) ; \
|
||||
exit 1; } >&2
|
||||
check-am: all-am
|
||||
check: check-recursive
|
||||
all-am: Makefile $(PROGRAMS) config.h
|
||||
installdirs: installdirs-recursive
|
||||
installdirs-am:
|
||||
install: install-recursive
|
||||
install-exec: install-exec-recursive
|
||||
install-data: install-data-recursive
|
||||
uninstall: uninstall-recursive
|
||||
|
||||
install-am: all-am
|
||||
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
|
||||
|
||||
installcheck: installcheck-recursive
|
||||
install-strip:
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
`test -z '$(STRIP)' || \
|
||||
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
|
||||
mostlyclean-generic:
|
||||
|
||||
clean-generic:
|
||||
|
||||
distclean-generic:
|
||||
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
|
||||
|
||||
maintainer-clean-generic:
|
||||
@echo "This command is intended for maintainers to use"
|
||||
@echo "it deletes files that may require special tools to rebuild."
|
||||
clean: clean-recursive
|
||||
|
||||
clean-am: clean-generic clean-noinstPROGRAMS mostlyclean-am
|
||||
|
||||
distclean: distclean-recursive
|
||||
-rm -f $(am__CONFIG_DISTCLEAN_FILES)
|
||||
-rm -rf ./$(DEPDIR)
|
||||
-rm -f Makefile
|
||||
distclean-am: clean-am distclean-compile distclean-generic \
|
||||
distclean-hdr distclean-tags
|
||||
|
||||
dvi: dvi-recursive
|
||||
|
||||
dvi-am:
|
||||
|
||||
html: html-recursive
|
||||
|
||||
info: info-recursive
|
||||
|
||||
info-am:
|
||||
|
||||
install-data-am: install-data-local
|
||||
|
||||
install-exec-am: install-exec-local
|
||||
|
||||
install-info: install-info-recursive
|
||||
|
||||
install-man:
|
||||
|
||||
installcheck-am:
|
||||
|
||||
maintainer-clean: maintainer-clean-recursive
|
||||
-rm -f $(am__CONFIG_DISTCLEAN_FILES)
|
||||
-rm -rf $(top_srcdir)/autom4te.cache
|
||||
-rm -rf ./$(DEPDIR)
|
||||
-rm -f Makefile
|
||||
maintainer-clean-am: distclean-am maintainer-clean-generic
|
||||
|
||||
mostlyclean: mostlyclean-recursive
|
||||
|
||||
mostlyclean-am: mostlyclean-compile mostlyclean-generic
|
||||
|
||||
pdf: pdf-recursive
|
||||
|
||||
pdf-am:
|
||||
|
||||
ps: ps-recursive
|
||||
|
||||
ps-am:
|
||||
|
||||
uninstall-am: uninstall-info-am
|
||||
|
||||
uninstall-info: uninstall-info-recursive
|
||||
|
||||
.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am am--refresh check \
|
||||
check-am clean clean-generic clean-noinstPROGRAMS \
|
||||
clean-recursive ctags ctags-recursive dist dist-all dist-bzip2 \
|
||||
dist-gzip dist-shar dist-tarZ dist-zip distcheck distclean \
|
||||
distclean-compile distclean-generic distclean-hdr \
|
||||
distclean-recursive distclean-tags distcleancheck distdir \
|
||||
distuninstallcheck dvi dvi-am html html-am info info-am \
|
||||
install install-am install-data install-data-am \
|
||||
install-data-local install-exec install-exec-am \
|
||||
install-exec-local install-info install-info-am install-man \
|
||||
install-strip installcheck installcheck-am installdirs \
|
||||
installdirs-am maintainer-clean maintainer-clean-generic \
|
||||
maintainer-clean-recursive mostlyclean mostlyclean-compile \
|
||||
mostlyclean-generic mostlyclean-recursive pdf pdf-am ps ps-am \
|
||||
tags tags-recursive uninstall uninstall-am uninstall-info-am
|
||||
|
||||
|
||||
po/POTFILES.in: @MAINT@ Makefile
|
||||
for f in $(POTFILES); do echo $$f; done | LC_COLLATE= sort > tmp \
|
||||
&& mv tmp $(srcdir)/po/POTFILES.in
|
||||
|
||||
.PHONY: install-exec-local
|
||||
|
||||
install-exec-local: ld-new$(EXEEXT)
|
||||
$(mkinstalldirs) $(DESTDIR)$(bindir) $(DESTDIR)$(tooldir)/bin
|
||||
n=`echo ld | sed '$(transform)'; \
|
||||
$(INSTALL_PROGRAM) ld-new$(EXEEXT) $(DESTDIR)$(bindir)/$${n}$(EXEEXT); \
|
||||
if test "$(bindir)" != "$(tooldir)/bin"; then \
|
||||
rm -f $(DESTDIR)$(tooldir)/bin/ld$(EXEEXT); \
|
||||
ln $(DESTDIR)$(bindir)/$${n}$(EXEEXT) $(DESTDIR)$(tooldir)/bin/ld$(EXEEXT) >/dev/null 2>/dev/null \
|
||||
|| $(INSTALL_PROGRAM) ld-new$(EXEEXT) $(DESTDIR)$(tooldir)/bin/ld$(EXEEXT); \
|
||||
fi
|
||||
|
||||
# We want install to imply install-info as per GNU standards, despite
|
||||
# the cygnus option.
|
||||
install-data-local: install-info
|
||||
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
||||
# Otherwise a system limit (for SysV at least) may be exceeded.
|
||||
.NOEXPORT:
|
|
@ -0,0 +1,18 @@
|
|||
gold is an ELF linker. It is intended to have complete support for
|
||||
ELF and to run as fast as possible on modern systems.
|
||||
|
||||
It is written in C++. It is (intended to be) a GNU program, and
|
||||
therefore follows the GNU formatting standards as modified for C++.
|
||||
Source documents in order of precedence:
|
||||
http://www.gnu.org/prep/standards/
|
||||
http://gcc.gnu.org/onlinedocs/libstdc++/17_intro/C++STYLE
|
||||
http://www.zembu.com/eng/procs/c++style.html
|
||||
|
||||
The linker is intended to have complete support for cross-compilation,
|
||||
which still supporting the normal case of native linking as fast as
|
||||
possible. This makes the code more complex.
|
||||
|
||||
Many functions are actually templates whose parameter is the ELF file
|
||||
class (e.g., 32 bits or 64 bits). The code is the same, but we don't
|
||||
want to pay the execution time cost of always using 64-bit integers if
|
||||
the target is 32 bits.
|
|
@ -0,0 +1,877 @@
|
|||
# generated automatically by aclocal 1.9.5 -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
|
||||
# 2005 Free Software Foundation, Inc.
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
# Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# AM_AUTOMAKE_VERSION(VERSION)
|
||||
# ----------------------------
|
||||
# Automake X.Y traces this macro to ensure aclocal.m4 has been
|
||||
# generated from the m4 files accompanying Automake X.Y.
|
||||
AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version="1.9"])
|
||||
|
||||
# AM_SET_CURRENT_AUTOMAKE_VERSION
|
||||
# -------------------------------
|
||||
# Call AM_AUTOMAKE_VERSION so it can be traced.
|
||||
# This function is AC_REQUIREd by AC_INIT_AUTOMAKE.
|
||||
AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
|
||||
[AM_AUTOMAKE_VERSION([1.9.5])])
|
||||
|
||||
# AM_AUX_DIR_EXPAND -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
|
||||
# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to
|
||||
# `$srcdir', `$srcdir/..', or `$srcdir/../..'.
|
||||
#
|
||||
# Of course, Automake must honor this variable whenever it calls a
|
||||
# tool from the auxiliary directory. The problem is that $srcdir (and
|
||||
# therefore $ac_aux_dir as well) can be either absolute or relative,
|
||||
# depending on how configure is run. This is pretty annoying, since
|
||||
# it makes $ac_aux_dir quite unusable in subdirectories: in the top
|
||||
# source directory, any form will work fine, but in subdirectories a
|
||||
# relative path needs to be adjusted first.
|
||||
#
|
||||
# $ac_aux_dir/missing
|
||||
# fails when called from a subdirectory if $ac_aux_dir is relative
|
||||
# $top_srcdir/$ac_aux_dir/missing
|
||||
# fails if $ac_aux_dir is absolute,
|
||||
# fails when called from a subdirectory in a VPATH build with
|
||||
# a relative $ac_aux_dir
|
||||
#
|
||||
# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
|
||||
# are both prefixed by $srcdir. In an in-source build this is usually
|
||||
# harmless because $srcdir is `.', but things will broke when you
|
||||
# start a VPATH build or use an absolute $srcdir.
|
||||
#
|
||||
# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
|
||||
# iff we strip the leading $srcdir from $ac_aux_dir. That would be:
|
||||
# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"`
|
||||
# and then we would define $MISSING as
|
||||
# MISSING="\${SHELL} $am_aux_dir/missing"
|
||||
# This will work as long as MISSING is not called from configure, because
|
||||
# unfortunately $(top_srcdir) has no meaning in configure.
|
||||
# However there are other variables, like CC, which are often used in
|
||||
# configure, and could therefore not use this "fixed" $ac_aux_dir.
|
||||
#
|
||||
# Another solution, used here, is to always expand $ac_aux_dir to an
|
||||
# absolute PATH. The drawback is that using absolute paths prevent a
|
||||
# configured tree to be moved without reconfiguration.
|
||||
|
||||
AC_DEFUN([AM_AUX_DIR_EXPAND],
|
||||
[dnl Rely on autoconf to set up CDPATH properly.
|
||||
AC_PREREQ([2.50])dnl
|
||||
# expand $ac_aux_dir to an absolute path
|
||||
am_aux_dir=`cd $ac_aux_dir && pwd`
|
||||
])
|
||||
|
||||
# AM_CONDITIONAL -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005
|
||||
# Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 7
|
||||
|
||||
# AM_CONDITIONAL(NAME, SHELL-CONDITION)
|
||||
# -------------------------------------
|
||||
# Define a conditional.
|
||||
AC_DEFUN([AM_CONDITIONAL],
|
||||
[AC_PREREQ(2.52)dnl
|
||||
ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])],
|
||||
[$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
|
||||
AC_SUBST([$1_TRUE])
|
||||
AC_SUBST([$1_FALSE])
|
||||
if $2; then
|
||||
$1_TRUE=
|
||||
$1_FALSE='#'
|
||||
else
|
||||
$1_TRUE='#'
|
||||
$1_FALSE=
|
||||
fi
|
||||
AC_CONFIG_COMMANDS_PRE(
|
||||
[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
|
||||
AC_MSG_ERROR([[conditional "$1" was never defined.
|
||||
Usually this means the macro was only invoked conditionally.]])
|
||||
fi])])
|
||||
|
||||
|
||||
# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005
|
||||
# Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 8
|
||||
|
||||
# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be
|
||||
# written in clear, in which case automake, when reading aclocal.m4,
|
||||
# will think it sees a *use*, and therefore will trigger all it's
|
||||
# C support machinery. Also note that it means that autoscan, seeing
|
||||
# CC etc. in the Makefile, will ask for an AC_PROG_CC use...
|
||||
|
||||
|
||||
# _AM_DEPENDENCIES(NAME)
|
||||
# ----------------------
|
||||
# See how the compiler implements dependency checking.
|
||||
# NAME is "CC", "CXX", "GCJ", or "OBJC".
|
||||
# We try a few techniques and use that to set a single cache variable.
|
||||
#
|
||||
# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was
|
||||
# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular
|
||||
# dependency, and given that the user is not expected to run this macro,
|
||||
# just rely on AC_PROG_CC.
|
||||
AC_DEFUN([_AM_DEPENDENCIES],
|
||||
[AC_REQUIRE([AM_SET_DEPDIR])dnl
|
||||
AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl
|
||||
AC_REQUIRE([AM_MAKE_INCLUDE])dnl
|
||||
AC_REQUIRE([AM_DEP_TRACK])dnl
|
||||
|
||||
ifelse([$1], CC, [depcc="$CC" am_compiler_list=],
|
||||
[$1], CXX, [depcc="$CXX" am_compiler_list=],
|
||||
[$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'],
|
||||
[$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'],
|
||||
[depcc="$$1" am_compiler_list=])
|
||||
|
||||
AC_CACHE_CHECK([dependency style of $depcc],
|
||||
[am_cv_$1_dependencies_compiler_type],
|
||||
[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
|
||||
# We make a subdir and do the tests there. Otherwise we can end up
|
||||
# making bogus files that we don't know about and never remove. For
|
||||
# instance it was reported that on HP-UX the gcc test will end up
|
||||
# making a dummy file named `D' -- because `-MD' means `put the output
|
||||
# in D'.
|
||||
mkdir conftest.dir
|
||||
# Copy depcomp to subdir because otherwise we won't find it if we're
|
||||
# using a relative directory.
|
||||
cp "$am_depcomp" conftest.dir
|
||||
cd conftest.dir
|
||||
# We will build objects and dependencies in a subdirectory because
|
||||
# it helps to detect inapplicable dependency modes. For instance
|
||||
# both Tru64's cc and ICC support -MD to output dependencies as a
|
||||
# side effect of compilation, but ICC will put the dependencies in
|
||||
# the current directory while Tru64 will put them in the object
|
||||
# directory.
|
||||
mkdir sub
|
||||
|
||||
am_cv_$1_dependencies_compiler_type=none
|
||||
if test "$am_compiler_list" = ""; then
|
||||
am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp`
|
||||
fi
|
||||
for depmode in $am_compiler_list; do
|
||||
# Setup a source with many dependencies, because some compilers
|
||||
# like to wrap large dependency lists on column 80 (with \), and
|
||||
# we should not choose a depcomp mode which is confused by this.
|
||||
#
|
||||
# We need to recreate these files for each test, as the compiler may
|
||||
# overwrite some of them when testing with obscure command lines.
|
||||
# This happens at least with the AIX C compiler.
|
||||
: > sub/conftest.c
|
||||
for i in 1 2 3 4 5 6; do
|
||||
echo '#include "conftst'$i'.h"' >> sub/conftest.c
|
||||
# Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
|
||||
# Solaris 8's {/usr,}/bin/sh.
|
||||
touch sub/conftst$i.h
|
||||
done
|
||||
echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
|
||||
|
||||
case $depmode in
|
||||
nosideeffect)
|
||||
# after this tag, mechanisms are not by side-effect, so they'll
|
||||
# only be used when explicitly requested
|
||||
if test "x$enable_dependency_tracking" = xyes; then
|
||||
continue
|
||||
else
|
||||
break
|
||||
fi
|
||||
;;
|
||||
none) break ;;
|
||||
esac
|
||||
# We check with `-c' and `-o' for the sake of the "dashmstdout"
|
||||
# mode. It turns out that the SunPro C++ compiler does not properly
|
||||
# handle `-M -o', and we need to detect this.
|
||||
if depmode=$depmode \
|
||||
source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \
|
||||
depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
|
||||
$SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \
|
||||
>/dev/null 2>conftest.err &&
|
||||
grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
|
||||
grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 &&
|
||||
${MAKE-make} -s -f confmf > /dev/null 2>&1; then
|
||||
# icc doesn't choke on unknown options, it will just issue warnings
|
||||
# or remarks (even with -Werror). So we grep stderr for any message
|
||||
# that says an option was ignored or not supported.
|
||||
# When given -MP, icc 7.0 and 7.1 complain thusly:
|
||||
# icc: Command line warning: ignoring option '-M'; no argument required
|
||||
# The diagnosis changed in icc 8.0:
|
||||
# icc: Command line remark: option '-MP' not supported
|
||||
if (grep 'ignoring option' conftest.err ||
|
||||
grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
|
||||
am_cv_$1_dependencies_compiler_type=$depmode
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
cd ..
|
||||
rm -rf conftest.dir
|
||||
else
|
||||
am_cv_$1_dependencies_compiler_type=none
|
||||
fi
|
||||
])
|
||||
AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type])
|
||||
AM_CONDITIONAL([am__fastdep$1], [
|
||||
test "x$enable_dependency_tracking" != xno \
|
||||
&& test "$am_cv_$1_dependencies_compiler_type" = gcc3])
|
||||
])
|
||||
|
||||
|
||||
# AM_SET_DEPDIR
|
||||
# -------------
|
||||
# Choose a directory name for dependency files.
|
||||
# This macro is AC_REQUIREd in _AM_DEPENDENCIES
|
||||
AC_DEFUN([AM_SET_DEPDIR],
|
||||
[AC_REQUIRE([AM_SET_LEADING_DOT])dnl
|
||||
AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl
|
||||
])
|
||||
|
||||
|
||||
# AM_DEP_TRACK
|
||||
# ------------
|
||||
AC_DEFUN([AM_DEP_TRACK],
|
||||
[AC_ARG_ENABLE(dependency-tracking,
|
||||
[ --disable-dependency-tracking speeds up one-time build
|
||||
--enable-dependency-tracking do not reject slow dependency extractors])
|
||||
if test "x$enable_dependency_tracking" != xno; then
|
||||
am_depcomp="$ac_aux_dir/depcomp"
|
||||
AMDEPBACKSLASH='\'
|
||||
fi
|
||||
AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
|
||||
AC_SUBST([AMDEPBACKSLASH])
|
||||
])
|
||||
|
||||
# Generate code to set up dependency tracking. -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005
|
||||
# Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
#serial 3
|
||||
|
||||
# _AM_OUTPUT_DEPENDENCY_COMMANDS
|
||||
# ------------------------------
|
||||
AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
|
||||
[for mf in $CONFIG_FILES; do
|
||||
# Strip MF so we end up with the name of the file.
|
||||
mf=`echo "$mf" | sed -e 's/:.*$//'`
|
||||
# Check whether this is an Automake generated Makefile or not.
|
||||
# We used to match only the files named `Makefile.in', but
|
||||
# some people rename them; so instead we look at the file content.
|
||||
# Grep'ing the first line is not enough: some people post-process
|
||||
# each Makefile.in and add a new line on top of each file to say so.
|
||||
# So let's grep whole file.
|
||||
if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then
|
||||
dirpart=`AS_DIRNAME("$mf")`
|
||||
else
|
||||
continue
|
||||
fi
|
||||
# Extract the definition of DEPDIR, am__include, and am__quote
|
||||
# from the Makefile without running `make'.
|
||||
DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
|
||||
test -z "$DEPDIR" && continue
|
||||
am__include=`sed -n 's/^am__include = //p' < "$mf"`
|
||||
test -z "am__include" && continue
|
||||
am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
|
||||
# When using ansi2knr, U may be empty or an underscore; expand it
|
||||
U=`sed -n 's/^U = //p' < "$mf"`
|
||||
# Find all dependency output files, they are included files with
|
||||
# $(DEPDIR) in their names. We invoke sed twice because it is the
|
||||
# simplest approach to changing $(DEPDIR) to its actual value in the
|
||||
# expansion.
|
||||
for file in `sed -n "
|
||||
s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
|
||||
sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
|
||||
# Make sure the directory exists.
|
||||
test -f "$dirpart/$file" && continue
|
||||
fdir=`AS_DIRNAME(["$file"])`
|
||||
AS_MKDIR_P([$dirpart/$fdir])
|
||||
# echo "creating $dirpart/$file"
|
||||
echo '# dummy' > "$dirpart/$file"
|
||||
done
|
||||
done
|
||||
])# _AM_OUTPUT_DEPENDENCY_COMMANDS
|
||||
|
||||
|
||||
# AM_OUTPUT_DEPENDENCY_COMMANDS
|
||||
# -----------------------------
|
||||
# This macro should only be invoked once -- use via AC_REQUIRE.
|
||||
#
|
||||
# This code is only required when automatic dependency tracking
|
||||
# is enabled. FIXME. This creates each `.P' file that we will
|
||||
# need in order to bootstrap the dependency handling code.
|
||||
AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
|
||||
[AC_CONFIG_COMMANDS([depfiles],
|
||||
[test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS],
|
||||
[AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"])
|
||||
])
|
||||
|
||||
# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005
|
||||
# Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 8
|
||||
|
||||
# AM_CONFIG_HEADER is obsolete. It has been replaced by AC_CONFIG_HEADERS.
|
||||
AU_DEFUN([AM_CONFIG_HEADER], [AC_CONFIG_HEADERS($@)])
|
||||
|
||||
# Do all the work for Automake. -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
|
||||
# Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 12
|
||||
|
||||
# This macro actually does too much. Some checks are only needed if
|
||||
# your package does certain things. But this isn't really a big deal.
|
||||
|
||||
# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
|
||||
# AM_INIT_AUTOMAKE([OPTIONS])
|
||||
# -----------------------------------------------
|
||||
# The call with PACKAGE and VERSION arguments is the old style
|
||||
# call (pre autoconf-2.50), which is being phased out. PACKAGE
|
||||
# and VERSION should now be passed to AC_INIT and removed from
|
||||
# the call to AM_INIT_AUTOMAKE.
|
||||
# We support both call styles for the transition. After
|
||||
# the next Automake release, Autoconf can make the AC_INIT
|
||||
# arguments mandatory, and then we can depend on a new Autoconf
|
||||
# release and drop the old call support.
|
||||
AC_DEFUN([AM_INIT_AUTOMAKE],
|
||||
[AC_PREREQ([2.58])dnl
|
||||
dnl Autoconf wants to disallow AM_ names. We explicitly allow
|
||||
dnl the ones we care about.
|
||||
m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
|
||||
AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
|
||||
AC_REQUIRE([AC_PROG_INSTALL])dnl
|
||||
# test to see if srcdir already configured
|
||||
if test "`cd $srcdir && pwd`" != "`pwd`" &&
|
||||
test -f $srcdir/config.status; then
|
||||
AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
|
||||
fi
|
||||
|
||||
# test whether we have cygpath
|
||||
if test -z "$CYGPATH_W"; then
|
||||
if (cygpath --version) >/dev/null 2>/dev/null; then
|
||||
CYGPATH_W='cygpath -w'
|
||||
else
|
||||
CYGPATH_W=echo
|
||||
fi
|
||||
fi
|
||||
AC_SUBST([CYGPATH_W])
|
||||
|
||||
# Define the identity of the package.
|
||||
dnl Distinguish between old-style and new-style calls.
|
||||
m4_ifval([$2],
|
||||
[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
|
||||
AC_SUBST([PACKAGE], [$1])dnl
|
||||
AC_SUBST([VERSION], [$2])],
|
||||
[_AM_SET_OPTIONS([$1])dnl
|
||||
AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
|
||||
AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl
|
||||
|
||||
_AM_IF_OPTION([no-define],,
|
||||
[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package])
|
||||
AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl
|
||||
|
||||
# Some tools Automake needs.
|
||||
AC_REQUIRE([AM_SANITY_CHECK])dnl
|
||||
AC_REQUIRE([AC_ARG_PROGRAM])dnl
|
||||
AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version})
|
||||
AM_MISSING_PROG(AUTOCONF, autoconf)
|
||||
AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version})
|
||||
AM_MISSING_PROG(AUTOHEADER, autoheader)
|
||||
AM_MISSING_PROG(MAKEINFO, makeinfo)
|
||||
AM_PROG_INSTALL_SH
|
||||
AM_PROG_INSTALL_STRIP
|
||||
AC_REQUIRE([AM_PROG_MKDIR_P])dnl
|
||||
# We need awk for the "check" target. The system "awk" is bad on
|
||||
# some platforms.
|
||||
AC_REQUIRE([AC_PROG_AWK])dnl
|
||||
AC_REQUIRE([AC_PROG_MAKE_SET])dnl
|
||||
AC_REQUIRE([AM_SET_LEADING_DOT])dnl
|
||||
_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])],
|
||||
[_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],
|
||||
[_AM_PROG_TAR([v7])])])
|
||||
_AM_IF_OPTION([no-dependencies],,
|
||||
[AC_PROVIDE_IFELSE([AC_PROG_CC],
|
||||
[_AM_DEPENDENCIES(CC)],
|
||||
[define([AC_PROG_CC],
|
||||
defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl
|
||||
AC_PROVIDE_IFELSE([AC_PROG_CXX],
|
||||
[_AM_DEPENDENCIES(CXX)],
|
||||
[define([AC_PROG_CXX],
|
||||
defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
# When config.status generates a header, we must update the stamp-h file.
|
||||
# This file resides in the same directory as the config header
|
||||
# that is generated. The stamp files are numbered to have different names.
|
||||
|
||||
# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the
|
||||
# loop where config.status creates the headers, so we can generate
|
||||
# our stamp files there.
|
||||
AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
|
||||
[# Compute $1's index in $config_headers.
|
||||
_am_stamp_count=1
|
||||
for _am_header in $config_headers :; do
|
||||
case $_am_header in
|
||||
$1 | $1:* )
|
||||
break ;;
|
||||
* )
|
||||
_am_stamp_count=`expr $_am_stamp_count + 1` ;;
|
||||
esac
|
||||
done
|
||||
echo "timestamp for $1" >`AS_DIRNAME([$1])`/stamp-h[]$_am_stamp_count])
|
||||
|
||||
# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# AM_PROG_INSTALL_SH
|
||||
# ------------------
|
||||
# Define $install_sh.
|
||||
AC_DEFUN([AM_PROG_INSTALL_SH],
|
||||
[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
|
||||
install_sh=${install_sh-"$am_aux_dir/install-sh"}
|
||||
AC_SUBST(install_sh)])
|
||||
|
||||
# Add --enable-maintainer-mode option to configure. -*- Autoconf -*-
|
||||
# From Jim Meyering
|
||||
|
||||
# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005
|
||||
# Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 4
|
||||
|
||||
AC_DEFUN([AM_MAINTAINER_MODE],
|
||||
[AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles])
|
||||
dnl maintainer-mode is disabled by default
|
||||
AC_ARG_ENABLE(maintainer-mode,
|
||||
[ --enable-maintainer-mode enable make rules and dependencies not useful
|
||||
(and sometimes confusing) to the casual installer],
|
||||
USE_MAINTAINER_MODE=$enableval,
|
||||
USE_MAINTAINER_MODE=no)
|
||||
AC_MSG_RESULT([$USE_MAINTAINER_MODE])
|
||||
AM_CONDITIONAL(MAINTAINER_MODE, [test $USE_MAINTAINER_MODE = yes])
|
||||
MAINT=$MAINTAINER_MODE_TRUE
|
||||
AC_SUBST(MAINT)dnl
|
||||
]
|
||||
)
|
||||
|
||||
AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE])
|
||||
|
||||
# Check to see how 'make' treats includes. -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 3
|
||||
|
||||
# AM_MAKE_INCLUDE()
|
||||
# -----------------
|
||||
# Check to see how make treats includes.
|
||||
AC_DEFUN([AM_MAKE_INCLUDE],
|
||||
[am_make=${MAKE-make}
|
||||
cat > confinc << 'END'
|
||||
am__doit:
|
||||
@echo done
|
||||
.PHONY: am__doit
|
||||
END
|
||||
# If we don't find an include directive, just comment out the code.
|
||||
AC_MSG_CHECKING([for style of include used by $am_make])
|
||||
am__include="#"
|
||||
am__quote=
|
||||
_am_result=none
|
||||
# First try GNU make style include.
|
||||
echo "include confinc" > confmf
|
||||
# We grep out `Entering directory' and `Leaving directory'
|
||||
# messages which can occur if `w' ends up in MAKEFLAGS.
|
||||
# In particular we don't look at `^make:' because GNU make might
|
||||
# be invoked under some other name (usually "gmake"), in which
|
||||
# case it prints its new name instead of `make'.
|
||||
if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then
|
||||
am__include=include
|
||||
am__quote=
|
||||
_am_result=GNU
|
||||
fi
|
||||
# Now try BSD make style include.
|
||||
if test "$am__include" = "#"; then
|
||||
echo '.include "confinc"' > confmf
|
||||
if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then
|
||||
am__include=.include
|
||||
am__quote="\""
|
||||
_am_result=BSD
|
||||
fi
|
||||
fi
|
||||
AC_SUBST([am__include])
|
||||
AC_SUBST([am__quote])
|
||||
AC_MSG_RESULT([$_am_result])
|
||||
rm -f confinc confmf
|
||||
])
|
||||
|
||||
# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2005
|
||||
# Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 4
|
||||
|
||||
# AM_MISSING_PROG(NAME, PROGRAM)
|
||||
# ------------------------------
|
||||
AC_DEFUN([AM_MISSING_PROG],
|
||||
[AC_REQUIRE([AM_MISSING_HAS_RUN])
|
||||
$1=${$1-"${am_missing_run}$2"}
|
||||
AC_SUBST($1)])
|
||||
|
||||
|
||||
# AM_MISSING_HAS_RUN
|
||||
# ------------------
|
||||
# Define MISSING if not defined so far and test if it supports --run.
|
||||
# If it does, set am_missing_run to use it, otherwise, to nothing.
|
||||
AC_DEFUN([AM_MISSING_HAS_RUN],
|
||||
[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
|
||||
test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing"
|
||||
# Use eval to expand $SHELL
|
||||
if eval "$MISSING --run true"; then
|
||||
am_missing_run="$MISSING --run "
|
||||
else
|
||||
am_missing_run=
|
||||
AC_MSG_WARN([`missing' script is too old or missing])
|
||||
fi
|
||||
])
|
||||
|
||||
# Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# AM_PROG_MKDIR_P
|
||||
# ---------------
|
||||
# Check whether `mkdir -p' is supported, fallback to mkinstalldirs otherwise.
|
||||
#
|
||||
# Automake 1.8 used `mkdir -m 0755 -p --' to ensure that directories
|
||||
# created by `make install' are always world readable, even if the
|
||||
# installer happens to have an overly restrictive umask (e.g. 077).
|
||||
# This was a mistake. There are at least two reasons why we must not
|
||||
# use `-m 0755':
|
||||
# - it causes special bits like SGID to be ignored,
|
||||
# - it may be too restrictive (some setups expect 775 directories).
|
||||
#
|
||||
# Do not use -m 0755 and let people choose whatever they expect by
|
||||
# setting umask.
|
||||
#
|
||||
# We cannot accept any implementation of `mkdir' that recognizes `-p'.
|
||||
# Some implementations (such as Solaris 8's) are not thread-safe: if a
|
||||
# parallel make tries to run `mkdir -p a/b' and `mkdir -p a/c'
|
||||
# concurrently, both version can detect that a/ is missing, but only
|
||||
# one can create it and the other will error out. Consequently we
|
||||
# restrict ourselves to GNU make (using the --version option ensures
|
||||
# this.)
|
||||
AC_DEFUN([AM_PROG_MKDIR_P],
|
||||
[if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then
|
||||
# We used to keeping the `.' as first argument, in order to
|
||||
# allow $(mkdir_p) to be used without argument. As in
|
||||
# $(mkdir_p) $(somedir)
|
||||
# where $(somedir) is conditionally defined. However this is wrong
|
||||
# for two reasons:
|
||||
# 1. if the package is installed by a user who cannot write `.'
|
||||
# make install will fail,
|
||||
# 2. the above comment should most certainly read
|
||||
# $(mkdir_p) $(DESTDIR)$(somedir)
|
||||
# so it does not work when $(somedir) is undefined and
|
||||
# $(DESTDIR) is not.
|
||||
# To support the latter case, we have to write
|
||||
# test -z "$(somedir)" || $(mkdir_p) $(DESTDIR)$(somedir),
|
||||
# so the `.' trick is pointless.
|
||||
mkdir_p='mkdir -p --'
|
||||
else
|
||||
# On NextStep and OpenStep, the `mkdir' command does not
|
||||
# recognize any option. It will interpret all options as
|
||||
# directories to create, and then abort because `.' already
|
||||
# exists.
|
||||
for d in ./-p ./--version;
|
||||
do
|
||||
test -d $d && rmdir $d
|
||||
done
|
||||
# $(mkinstalldirs) is defined by Automake if mkinstalldirs exists.
|
||||
if test -f "$ac_aux_dir/mkinstalldirs"; then
|
||||
mkdir_p='$(mkinstalldirs)'
|
||||
else
|
||||
mkdir_p='$(install_sh) -d'
|
||||
fi
|
||||
fi
|
||||
AC_SUBST([mkdir_p])])
|
||||
|
||||
# Helper functions for option handling. -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 3
|
||||
|
||||
# _AM_MANGLE_OPTION(NAME)
|
||||
# -----------------------
|
||||
AC_DEFUN([_AM_MANGLE_OPTION],
|
||||
[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
|
||||
|
||||
# _AM_SET_OPTION(NAME)
|
||||
# ------------------------------
|
||||
# Set option NAME. Presently that only means defining a flag for this option.
|
||||
AC_DEFUN([_AM_SET_OPTION],
|
||||
[m4_define(_AM_MANGLE_OPTION([$1]), 1)])
|
||||
|
||||
# _AM_SET_OPTIONS(OPTIONS)
|
||||
# ----------------------------------
|
||||
# OPTIONS is a space-separated list of Automake options.
|
||||
AC_DEFUN([_AM_SET_OPTIONS],
|
||||
[AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
|
||||
|
||||
# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
|
||||
# -------------------------------------------
|
||||
# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
|
||||
AC_DEFUN([_AM_IF_OPTION],
|
||||
[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
|
||||
|
||||
# Check to make sure that the build environment is sane. -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005
|
||||
# Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 4
|
||||
|
||||
# AM_SANITY_CHECK
|
||||
# ---------------
|
||||
AC_DEFUN([AM_SANITY_CHECK],
|
||||
[AC_MSG_CHECKING([whether build environment is sane])
|
||||
# Just in case
|
||||
sleep 1
|
||||
echo timestamp > conftest.file
|
||||
# Do `set' in a subshell so we don't clobber the current shell's
|
||||
# arguments. Must try -L first in case configure is actually a
|
||||
# symlink; some systems play weird games with the mod time of symlinks
|
||||
# (eg FreeBSD returns the mod time of the symlink's containing
|
||||
# directory).
|
||||
if (
|
||||
set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null`
|
||||
if test "$[*]" = "X"; then
|
||||
# -L didn't work.
|
||||
set X `ls -t $srcdir/configure conftest.file`
|
||||
fi
|
||||
rm -f conftest.file
|
||||
if test "$[*]" != "X $srcdir/configure conftest.file" \
|
||||
&& test "$[*]" != "X conftest.file $srcdir/configure"; then
|
||||
|
||||
# If neither matched, then we have a broken ls. This can happen
|
||||
# if, for instance, CONFIG_SHELL is bash and it inherits a
|
||||
# broken ls alias from the environment. This has actually
|
||||
# happened. Such a system could not be considered "sane".
|
||||
AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken
|
||||
alias in your environment])
|
||||
fi
|
||||
|
||||
test "$[2]" = conftest.file
|
||||
)
|
||||
then
|
||||
# Ok.
|
||||
:
|
||||
else
|
||||
AC_MSG_ERROR([newly created file is older than distributed files!
|
||||
Check your system clock])
|
||||
fi
|
||||
AC_MSG_RESULT(yes)])
|
||||
|
||||
# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# AM_PROG_INSTALL_STRIP
|
||||
# ---------------------
|
||||
# One issue with vendor `install' (even GNU) is that you can't
|
||||
# specify the program used to strip binaries. This is especially
|
||||
# annoying in cross-compiling environments, where the build's strip
|
||||
# is unlikely to handle the host's binaries.
|
||||
# Fortunately install-sh will honor a STRIPPROG variable, so we
|
||||
# always use install-sh in `make install-strip', and initialize
|
||||
# STRIPPROG with the value of the STRIP variable (set by the user).
|
||||
AC_DEFUN([AM_PROG_INSTALL_STRIP],
|
||||
[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
|
||||
# Installed binaries are usually stripped using `strip' when the user
|
||||
# run `make install-strip'. However `strip' might not be the right
|
||||
# tool to use in cross-compilation environments, therefore Automake
|
||||
# will honor the `STRIP' environment variable to overrule this program.
|
||||
dnl Don't test for $cross_compiling = yes, because it might be `maybe'.
|
||||
if test "$cross_compiling" != no; then
|
||||
AC_CHECK_TOOL([STRIP], [strip], :)
|
||||
fi
|
||||
INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s"
|
||||
AC_SUBST([INSTALL_STRIP_PROGRAM])])
|
||||
|
||||
# Check how to create a tarball. -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 2004, 2005 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 2
|
||||
|
||||
# _AM_PROG_TAR(FORMAT)
|
||||
# --------------------
|
||||
# Check how to create a tarball in format FORMAT.
|
||||
# FORMAT should be one of `v7', `ustar', or `pax'.
|
||||
#
|
||||
# Substitute a variable $(am__tar) that is a command
|
||||
# writing to stdout a FORMAT-tarball containing the directory
|
||||
# $tardir.
|
||||
# tardir=directory && $(am__tar) > result.tar
|
||||
#
|
||||
# Substitute a variable $(am__untar) that extract such
|
||||
# a tarball read from stdin.
|
||||
# $(am__untar) < result.tar
|
||||
AC_DEFUN([_AM_PROG_TAR],
|
||||
[# Always define AMTAR for backward compatibility.
|
||||
AM_MISSING_PROG([AMTAR], [tar])
|
||||
m4_if([$1], [v7],
|
||||
[am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'],
|
||||
[m4_case([$1], [ustar],, [pax],,
|
||||
[m4_fatal([Unknown tar format])])
|
||||
AC_MSG_CHECKING([how to create a $1 tar archive])
|
||||
# Loop over all known methods to create a tar archive until one works.
|
||||
_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'
|
||||
_am_tools=${am_cv_prog_tar_$1-$_am_tools}
|
||||
# Do not fold the above two line into one, because Tru64 sh and
|
||||
# Solaris sh will not grok spaces in the rhs of `-'.
|
||||
for _am_tool in $_am_tools
|
||||
do
|
||||
case $_am_tool in
|
||||
gnutar)
|
||||
for _am_tar in tar gnutar gtar;
|
||||
do
|
||||
AM_RUN_LOG([$_am_tar --version]) && break
|
||||
done
|
||||
am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
|
||||
am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
|
||||
am__untar="$_am_tar -xf -"
|
||||
;;
|
||||
plaintar)
|
||||
# Must skip GNU tar: if it does not support --format= it doesn't create
|
||||
# ustar tarball either.
|
||||
(tar --version) >/dev/null 2>&1 && continue
|
||||
am__tar='tar chf - "$$tardir"'
|
||||
am__tar_='tar chf - "$tardir"'
|
||||
am__untar='tar xf -'
|
||||
;;
|
||||
pax)
|
||||
am__tar='pax -L -x $1 -w "$$tardir"'
|
||||
am__tar_='pax -L -x $1 -w "$tardir"'
|
||||
am__untar='pax -r'
|
||||
;;
|
||||
cpio)
|
||||
am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
|
||||
am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
|
||||
am__untar='cpio -i -H $1 -d'
|
||||
;;
|
||||
none)
|
||||
am__tar=false
|
||||
am__tar_=false
|
||||
am__untar=false
|
||||
;;
|
||||
esac
|
||||
|
||||
# If the value was cached, stop now. We just wanted to have am__tar
|
||||
# and am__untar set.
|
||||
test -n "${am_cv_prog_tar_$1}" && break
|
||||
|
||||
# tar/untar a dummy directory, and stop if the command works
|
||||
rm -rf conftest.dir
|
||||
mkdir conftest.dir
|
||||
echo GrepMe > conftest.dir/file
|
||||
AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
|
||||
rm -rf conftest.dir
|
||||
if test -s conftest.tar; then
|
||||
AM_RUN_LOG([$am__untar <conftest.tar])
|
||||
grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
|
||||
fi
|
||||
done
|
||||
rm -rf conftest.dir
|
||||
|
||||
AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
|
||||
AC_MSG_RESULT([$am_cv_prog_tar_$1])])
|
||||
AC_SUBST([am__tar])
|
||||
AC_SUBST([am__untar])
|
||||
]) # _AM_PROG_TAR
|
||||
|
||||
m4_include([../config/depstand.m4])
|
||||
m4_include([../config/lead-dot.m4])
|
||||
m4_include([../bfd/../config/progtest.m4])
|
||||
m4_include([../bfd/../config/po.m4])
|
||||
m4_include([../bfd/../config/nls.m4])
|
||||
m4_include([../bfd/../config/gettext-sister.m4])
|
||||
m4_include([../bfd/warning.m4])
|
|
@ -0,0 +1,26 @@
|
|||
/* config.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Define to 1 if translation of program messages to the user's native
|
||||
language is requested. */
|
||||
#undef ENABLE_NLS
|
||||
|
||||
/* Name of package */
|
||||
#undef PACKAGE
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#undef PACKAGE_BUGREPORT
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#undef PACKAGE_NAME
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#undef PACKAGE_STRING
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#undef PACKAGE_TARNAME
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
/* Version number of package */
|
||||
#undef VERSION
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,33 @@
|
|||
dnl Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_PREREQ(2.59)
|
||||
AC_INIT
|
||||
AC_CONFIG_SRCDIR([gold.cc])
|
||||
|
||||
AC_CANONICAL_TARGET
|
||||
|
||||
AM_INIT_AUTOMAKE(gold, 0.1)
|
||||
|
||||
AM_CONFIG_HEADER(config.h:config.in)
|
||||
|
||||
AC_PROG_CC
|
||||
AC_PROG_CXX
|
||||
AC_PROG_INSTALL
|
||||
ZW_GNU_GETTEXT_SISTER_DIR
|
||||
AM_PO_SUBDIRS
|
||||
|
||||
AC_EXEEXT
|
||||
|
||||
AM_BINUTILS_WARNINGS
|
||||
|
||||
WARN_CXXFLAGS=`echo ${WARN_CFLAGS} | sed -e 's/-Wstrict-prototypes//' -e 's/-Wmissing-prototypes//'`
|
||||
AC_SUBST(WARN_CXXFLAGS)
|
||||
|
||||
dnl Force support for large files by default. This may need to be
|
||||
dnl host dependent. If build == host, we can check getconf LFS_CFLAGS.
|
||||
LFS_CXXFLAGS="-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64"
|
||||
AC_SUBST(LFS_CXXFLAGS)
|
||||
|
||||
AM_MAINTAINER_MODE
|
||||
|
||||
AC_OUTPUT(Makefile po/Makefile.in:po/Make-in)
|
|
@ -0,0 +1,236 @@
|
|||
// dirsearch.cc -- directory searching for gold
|
||||
|
||||
#include "gold.h"
|
||||
|
||||
#include <cerrno>
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include "gold-threads.h"
|
||||
#include "dirsearch.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
// Read all the files in a directory.
|
||||
|
||||
class Dir_cache
|
||||
{
|
||||
public:
|
||||
Dir_cache(const char* dirname)
|
||||
: dirname_(dirname), files_()
|
||||
{ }
|
||||
|
||||
// Read the files in the directory.
|
||||
void read_files();
|
||||
|
||||
// Return whether a file (a base name) is present in the directory.
|
||||
bool find(const std::string&) const;
|
||||
|
||||
private:
|
||||
// We can not copy this class.
|
||||
Dir_cache(const Dir_cache&);
|
||||
Dir_cache& operator=(const Dir_cache&);
|
||||
|
||||
const char* dirname_;
|
||||
Unordered_set<std::string> files_;
|
||||
};
|
||||
|
||||
void
|
||||
Dir_cache::read_files()
|
||||
{
|
||||
DIR* d = opendir(this->dirname_);
|
||||
if (d == NULL)
|
||||
{
|
||||
// We ignore directories which do not exist.
|
||||
if (errno == ENOENT)
|
||||
return;
|
||||
|
||||
char *s = NULL;
|
||||
if (asprintf(&s, _("can not read directory %s"), this->dirname_) < 0)
|
||||
gold::gold_nomem();
|
||||
gold::gold_fatal(s, true);
|
||||
}
|
||||
|
||||
dirent* de;
|
||||
while ((de = readdir(d)) != NULL)
|
||||
this->files_.insert(std::string(de->d_name));
|
||||
|
||||
if (closedir(d) != 0)
|
||||
gold::gold_fatal("closedir failed", true);
|
||||
}
|
||||
|
||||
bool
|
||||
Dir_cache::find(const std::string& basename) const
|
||||
{
|
||||
return this->files_.find(basename) != this->files_.end();
|
||||
}
|
||||
|
||||
// A mapping from directory names to caches. A lock permits
|
||||
// concurrent update. There is no lock for read operations--some
|
||||
// other mechanism must be used to prevent reads from conflicting with
|
||||
// writes.
|
||||
|
||||
class Dir_caches
|
||||
{
|
||||
public:
|
||||
Dir_caches()
|
||||
: lock_(), caches_()
|
||||
{ }
|
||||
|
||||
~Dir_caches();
|
||||
|
||||
// Add a cache for a directory.
|
||||
void add(const char*);
|
||||
|
||||
// Look up a directory in the cache. This much be locked against
|
||||
// calls to Add.
|
||||
Dir_cache* lookup(const char*) const;
|
||||
|
||||
private:
|
||||
// We can not copy this class.
|
||||
Dir_caches(const Dir_caches&);
|
||||
Dir_caches& operator=(const Dir_caches&);
|
||||
|
||||
typedef Unordered_map<const char*, Dir_cache*> Cache_hash;
|
||||
|
||||
gold::Lock lock_;
|
||||
Cache_hash caches_;
|
||||
};
|
||||
|
||||
Dir_caches::~Dir_caches()
|
||||
{
|
||||
for (Cache_hash::iterator p = this->caches_.begin();
|
||||
p != this->caches_.end();
|
||||
++p)
|
||||
delete p->second;
|
||||
}
|
||||
|
||||
void
|
||||
Dir_caches::add(const char* dirname)
|
||||
{
|
||||
{
|
||||
gold::Hold_lock hl(this->lock_);
|
||||
if (this->lookup(dirname) != NULL)
|
||||
return;
|
||||
}
|
||||
|
||||
Dir_cache* cache = new Dir_cache(dirname);
|
||||
|
||||
cache->read_files();
|
||||
|
||||
{
|
||||
gold::Hold_lock hl(this->lock_);
|
||||
|
||||
std::pair<const char*, Dir_cache*> v(dirname, cache);
|
||||
std::pair<Cache_hash::iterator, bool> p = this->caches_.insert(v);
|
||||
assert(p.second);
|
||||
}
|
||||
}
|
||||
|
||||
Dir_cache*
|
||||
Dir_caches::lookup(const char* dirname) const
|
||||
{
|
||||
Cache_hash::const_iterator p = this->caches_.find(dirname);
|
||||
if (p == this->caches_.end())
|
||||
return NULL;
|
||||
return p->second;
|
||||
}
|
||||
|
||||
// The caches.
|
||||
|
||||
Dir_caches caches;
|
||||
|
||||
// A Task to read the directory.
|
||||
|
||||
class Dir_cache_task : public gold::Task
|
||||
{
|
||||
public:
|
||||
Dir_cache_task(const char* dir, gold::Task_token& token)
|
||||
: dir_(dir), token_(token)
|
||||
{ }
|
||||
|
||||
Is_runnable_type is_runnable(gold::Workqueue*);
|
||||
|
||||
gold::Task_locker* locks(gold::Workqueue*);
|
||||
|
||||
void run(gold::Workqueue*);
|
||||
|
||||
private:
|
||||
const char* dir_;
|
||||
gold::Task_token& token_;
|
||||
};
|
||||
|
||||
// We can always run the task to read the directory.
|
||||
|
||||
gold::Task::Is_runnable_type
|
||||
Dir_cache_task::is_runnable(gold::Workqueue*)
|
||||
{
|
||||
return IS_RUNNABLE;
|
||||
}
|
||||
|
||||
// Return the locks to hold. We use a blocker lock to prevent file
|
||||
// lookups from starting until the directory contents have been read.
|
||||
|
||||
gold::Task_locker*
|
||||
Dir_cache_task::locks(gold::Workqueue* workqueue)
|
||||
{
|
||||
return new gold::Task_locker_block(this->token_, workqueue);
|
||||
}
|
||||
|
||||
// Run the task--read the directory contents.
|
||||
|
||||
void
|
||||
Dir_cache_task::run(gold::Workqueue*)
|
||||
{
|
||||
caches.add(this->dir_);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
||||
Dirsearch::Dirsearch()
|
||||
: directories_(), token_()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Dirsearch::add(Workqueue* workqueue, const char* d)
|
||||
{
|
||||
this->directories_.push_back(d);
|
||||
this->token_.add_blocker();
|
||||
workqueue->queue(new Dir_cache_task(d, this->token_));
|
||||
}
|
||||
|
||||
void
|
||||
Dirsearch::add(Workqueue* workqueue, const General_options::Dir_list& list)
|
||||
{
|
||||
for (General_options::Dir_list::const_iterator p = list.begin();
|
||||
p != list.end();
|
||||
++p)
|
||||
this->add(workqueue, *p);
|
||||
}
|
||||
|
||||
std::string
|
||||
Dirsearch::find(const std::string& n1, const std::string& n2) const
|
||||
{
|
||||
assert(!this->token_.is_blocked());
|
||||
|
||||
for (std::list<const char*>::const_iterator p = this->directories_.begin();
|
||||
p != this->directories_.end();
|
||||
++p)
|
||||
{
|
||||
Dir_cache* pdc = caches.lookup(*p);
|
||||
assert(pdc != NULL);
|
||||
if (pdc->find(n1))
|
||||
return std::string(*p) + '/' + n1;
|
||||
if (!n2.empty() && pdc->find(n2))
|
||||
return std::string(*p) + '/' + n2;
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
} // End namespace gold.
|
|
@ -0,0 +1,56 @@
|
|||
// dirsearch.h -- directory searching for gold -*- C++ -*-
|
||||
|
||||
#ifndef GOLD_DIRSEARCH_H
|
||||
#define GOLD_DIRSEARCH_H
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
#include "options.h"
|
||||
#include "workqueue.h"
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
||||
// A simple interface to manage directories to be searched for
|
||||
// libraries.
|
||||
|
||||
class Dirsearch
|
||||
{
|
||||
public:
|
||||
Dirsearch();
|
||||
|
||||
// Add a directory to the search path.
|
||||
void
|
||||
add(Workqueue*, const char*);
|
||||
|
||||
// Add a list of directories to the search path.
|
||||
void
|
||||
add(Workqueue*, const General_options::Dir_list&);
|
||||
|
||||
// Search for a file, giving one or two names to search for (the
|
||||
// second one may be empty). Return a full path name for the file,
|
||||
// or the empty string if it could not be found. This may only be
|
||||
// called if the token is not blocked.
|
||||
std::string
|
||||
find(const std::string&, const std::string& n2 = std::string()) const;
|
||||
|
||||
// Return a reference to the blocker token which controls access.
|
||||
const Task_token&
|
||||
token() const
|
||||
{ return this->token_; }
|
||||
|
||||
private:
|
||||
// We can not copy this class.
|
||||
Dirsearch(const Dirsearch&);
|
||||
Dirsearch& operator=(const Dirsearch&);
|
||||
|
||||
// Directories to search.
|
||||
std::list<const char*> directories_;
|
||||
// Blocker token to control access from tasks.
|
||||
Task_token token_;
|
||||
};
|
||||
|
||||
} // End namespace gold.
|
||||
|
||||
#endif // !defined(GOLD_DIRSEARCH_H)
|
|
@ -0,0 +1,281 @@
|
|||
// fileread.cc -- read files for gold
|
||||
|
||||
#include "gold.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <cerrno>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "options.h"
|
||||
#include "dirsearch.h"
|
||||
#include "fileread.h"
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
||||
// Class File_read::View.
|
||||
|
||||
File_read::View::~View()
|
||||
{
|
||||
assert(!this->is_locked());
|
||||
delete[] this->data_;
|
||||
}
|
||||
|
||||
void
|
||||
File_read::View::lock()
|
||||
{
|
||||
++this->lock_count_;
|
||||
}
|
||||
|
||||
void
|
||||
File_read::View::unlock()
|
||||
{
|
||||
assert(this->lock_count_ > 0);
|
||||
--this->lock_count_;
|
||||
}
|
||||
|
||||
bool
|
||||
File_read::View::is_locked()
|
||||
{
|
||||
return this->lock_count_ > 0;
|
||||
}
|
||||
|
||||
// Class File_read.
|
||||
|
||||
// The File_read class is designed to support file descriptor caching,
|
||||
// but this is not currently implemented.
|
||||
|
||||
File_read::~File_read()
|
||||
{
|
||||
assert(this->lock_count_ == 0);
|
||||
if (this->descriptor_ >= 0)
|
||||
{
|
||||
if (close(this->descriptor_) < 0)
|
||||
fprintf(stderr, _("%s: warning: close(%s) failed: %s"),
|
||||
program_name, this->name_.c_str(), strerror(errno));
|
||||
this->descriptor_ = -1;
|
||||
}
|
||||
this->name_.clear();
|
||||
this->clear_views(true);
|
||||
}
|
||||
|
||||
bool
|
||||
File_read::open(const std::string& name)
|
||||
{
|
||||
assert(this->lock_count_ == 0
|
||||
&& this->descriptor_ < 0
|
||||
&& this->name_.empty());
|
||||
this->name_ = name;
|
||||
this->descriptor_ = ::open(this->name_.c_str(), O_RDONLY);
|
||||
++this->lock_count_;
|
||||
return this->descriptor_ >= 0;
|
||||
}
|
||||
|
||||
int
|
||||
File_read::get_descriptor()
|
||||
{
|
||||
assert(this->lock_count_ > 0);
|
||||
return this->descriptor_;
|
||||
}
|
||||
|
||||
void
|
||||
File_read::lock()
|
||||
{
|
||||
++this->lock_count_;
|
||||
}
|
||||
|
||||
void
|
||||
File_read::unlock()
|
||||
{
|
||||
assert(this->lock_count_ > 0);
|
||||
--this->lock_count_;
|
||||
}
|
||||
|
||||
bool
|
||||
File_read::is_locked()
|
||||
{
|
||||
return this->lock_count_ > 0;
|
||||
}
|
||||
|
||||
// See if we have a view which covers the file starting at START for
|
||||
// SIZE bytes. Return a pointer to the View if found, NULL if not.
|
||||
|
||||
File_read::View*
|
||||
File_read::find_view(off_t start, off_t size)
|
||||
{
|
||||
for (std::list<File_read::View*>::iterator p = this->view_list_.begin();
|
||||
p != this->view_list_.end();
|
||||
++p)
|
||||
{
|
||||
if ((*p)->start() <= start
|
||||
&& (*p)->start() + (*p)->size() >= start + size)
|
||||
return *p;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Read data from the file. Return the number of bytes read. If
|
||||
// PBYTES is not NULL, store the number of bytes in *PBYTES, otherwise
|
||||
// require that we read exactly the number of bytes requested.
|
||||
|
||||
off_t
|
||||
File_read::do_read(off_t start, off_t size, void* p, off_t* pbytes)
|
||||
{
|
||||
assert(this->lock_count_ > 0);
|
||||
int o = this->descriptor_;
|
||||
|
||||
if (lseek(o, start, SEEK_SET) < 0)
|
||||
{
|
||||
fprintf(stderr, _("%s: %s: lseek to %lld failed: %s"),
|
||||
program_name, this->filename().c_str(),
|
||||
static_cast<long long>(start),
|
||||
strerror(errno));
|
||||
gold_exit(false);
|
||||
}
|
||||
|
||||
off_t bytes = ::read(o, p, size);
|
||||
if (bytes < 0)
|
||||
{
|
||||
fprintf(stderr, _("%s: %s: read failed: %s\n"),
|
||||
program_name, this->filename().c_str(), strerror(errno));
|
||||
gold_exit(false);
|
||||
}
|
||||
|
||||
if (pbytes != NULL)
|
||||
*pbytes = bytes;
|
||||
else if (bytes != size)
|
||||
{
|
||||
fprintf(stderr,
|
||||
_("%s: %s: file too short: read only %lld of %lld "
|
||||
"bytes at %lld\n"),
|
||||
program_name, this->filename().c_str(),
|
||||
static_cast<long long>(bytes),
|
||||
static_cast<long long>(size),
|
||||
static_cast<long long>(start));
|
||||
gold_exit(false);
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
void
|
||||
File_read::read(off_t start, off_t size, void* p, off_t* pbytes)
|
||||
{
|
||||
assert(this->lock_count_ > 0);
|
||||
|
||||
File_read::View* pv = this->find_view(start, size);
|
||||
if (pv != NULL)
|
||||
{
|
||||
memcpy(p, pv->data() + (start - pv->start()), size);
|
||||
if (pbytes != NULL)
|
||||
*pbytes = size;
|
||||
return;
|
||||
}
|
||||
|
||||
this->do_read(start, size, p, pbytes);
|
||||
}
|
||||
|
||||
// Find an existing view or make a new one.
|
||||
|
||||
File_read::View*
|
||||
File_read::find_or_make_view(off_t start, off_t size, off_t* pbytes)
|
||||
{
|
||||
assert(this->lock_count_ > 0);
|
||||
|
||||
File_read::View* pv = this->find_view(start, size);
|
||||
if (pv != NULL)
|
||||
return pv;
|
||||
|
||||
unsigned char* p = new unsigned char[size];
|
||||
off_t bytes = this->do_read(start, size, p, pbytes);
|
||||
pv = new File_read::View(start, bytes, p);
|
||||
this->view_list_.push_back(pv);
|
||||
return pv;
|
||||
}
|
||||
|
||||
// This implementation of get_view just reads into a memory buffer,
|
||||
// which we store on view_list_. At some point we should support
|
||||
// mmap.
|
||||
|
||||
const unsigned char*
|
||||
File_read::get_view(off_t start, off_t size, off_t* pbytes)
|
||||
{
|
||||
assert(this->lock_count_ > 0);
|
||||
File_read::View* pv = this->find_or_make_view(start, size, pbytes);
|
||||
return pv->data() + (start - pv->start());
|
||||
}
|
||||
|
||||
File_view*
|
||||
File_read::get_lasting_view(off_t start, off_t size, off_t* pbytes)
|
||||
{
|
||||
assert(this->lock_count_ > 0);
|
||||
File_read::View* pv = this->find_or_make_view(start, size, pbytes);
|
||||
pv->lock();
|
||||
return new File_view(*this, pv, pv->data() + (start - pv->start()));
|
||||
}
|
||||
|
||||
// Remove all the file views.
|
||||
|
||||
void
|
||||
File_read::clear_views(bool destroying)
|
||||
{
|
||||
std::list<File_read::View*>::iterator p = this->view_list_.begin();
|
||||
while (p != this->view_list_.end())
|
||||
{
|
||||
if ((*p)->is_locked())
|
||||
{
|
||||
assert(!destroying);
|
||||
++p;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete *p;
|
||||
p = this->view_list_.erase(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Class File_view.
|
||||
|
||||
File_view::~File_view()
|
||||
{
|
||||
assert(this->file_.is_locked());
|
||||
this->view_->unlock();
|
||||
}
|
||||
|
||||
// Class Input_file.
|
||||
|
||||
void
|
||||
Input_file::open(const General_options& options, const Dirsearch& dirpath)
|
||||
{
|
||||
std::string name;
|
||||
if (!this->input_argument_.is_lib())
|
||||
name = this->input_argument_.name();
|
||||
else
|
||||
{
|
||||
std::string n1("lib");
|
||||
n1 += this->input_argument_.lib_basename();
|
||||
std::string n2;
|
||||
if (options.is_static())
|
||||
n2 = n1 + ".so";
|
||||
n1 += ".a";
|
||||
name = dirpath.find(n1, n2);
|
||||
if (name.empty())
|
||||
{
|
||||
fprintf(stderr, _("%s: cannot find %s"), program_name,
|
||||
this->input_argument_.name());
|
||||
gold_exit(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (!this->file_.open(name))
|
||||
{
|
||||
fprintf(stderr, _("%s: cannot open %s: %s"), program_name, name.c_str(),
|
||||
strerror(errno));
|
||||
gold_exit(false);
|
||||
}
|
||||
}
|
||||
|
||||
} // End namespace gold.
|
|
@ -0,0 +1,226 @@
|
|||
// fileread.h -- read files for gold -*- C++ -*-
|
||||
|
||||
// Classes used to read data from binary input files.
|
||||
|
||||
#ifndef GOLD_FILEREAD_H
|
||||
#define GOLD_FILEREAD_H
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
#include "options.h"
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
||||
class Dirsearch;
|
||||
|
||||
class File_view;
|
||||
|
||||
// File_read manages a file descriptor for a file we are reading. We
|
||||
// close file descriptors if we run out of them, so this class reopens
|
||||
// the file as needed.
|
||||
|
||||
class File_read
|
||||
{
|
||||
public:
|
||||
File_read()
|
||||
: name_(), descriptor_(-1), lock_count_(0)
|
||||
{ }
|
||||
~File_read();
|
||||
|
||||
// Open a file.
|
||||
bool
|
||||
open(const std::string& name);
|
||||
|
||||
// Return the file name.
|
||||
const std::string&
|
||||
filename() const
|
||||
{ return this->name_; }
|
||||
|
||||
// Return the file descriptor.
|
||||
int
|
||||
get_descriptor();
|
||||
|
||||
// Lock the file for access within a particular Task::run execution.
|
||||
// This means that the descriptor can not be closed. This routine
|
||||
// may only be called from the main thread.
|
||||
void
|
||||
lock();
|
||||
|
||||
// Unlock the descriptor, permitting it to be closed if necessary.
|
||||
void
|
||||
unlock();
|
||||
|
||||
// Test whether the object is locked.
|
||||
bool
|
||||
is_locked();
|
||||
|
||||
// Return a view into the file. The pointer will remain valid until
|
||||
// the File_read is unlocked. If PBYTES is NULL, it is an error if
|
||||
// we can not read enough data. Otherwise *PBYTES is set to the
|
||||
// number of bytes read.
|
||||
const unsigned char*
|
||||
get_view(off_t start, off_t size, off_t *pbytes = NULL);
|
||||
|
||||
// Read data from the file into the buffer P. PBYTES is as in
|
||||
// get_view.
|
||||
void
|
||||
read(off_t start, off_t size, void* p, off_t *pbytes = NULL);
|
||||
|
||||
// Return a lasting view into the file. This is allocated with new,
|
||||
// and the caller is responsible for deleting it when done. The
|
||||
// data associated with this view will remain valid until the view
|
||||
// is deleted. PBYTES is handled as with get_view.
|
||||
File_view*
|
||||
get_lasting_view(off_t start, off_t size, off_t *pbytes = NULL);
|
||||
|
||||
private:
|
||||
// This class may not be copied.
|
||||
File_read(const File_read&);
|
||||
File_read& operator=(const File_read&);
|
||||
|
||||
// A view into the file when not using mmap.
|
||||
class View
|
||||
{
|
||||
public:
|
||||
View(off_t start, off_t size, unsigned char* data)
|
||||
: start_(start), size_(size), data_(data), lock_count_(0)
|
||||
{ }
|
||||
|
||||
~View();
|
||||
|
||||
off_t
|
||||
start() const
|
||||
{ return this->start_; }
|
||||
|
||||
off_t
|
||||
size() const
|
||||
{ return this->size_; }
|
||||
|
||||
unsigned char*
|
||||
data() const
|
||||
{ return this->data_; }
|
||||
|
||||
void
|
||||
lock();
|
||||
|
||||
void
|
||||
unlock();
|
||||
|
||||
bool
|
||||
is_locked();
|
||||
|
||||
private:
|
||||
View(const View&);
|
||||
View& operator=(const View&);
|
||||
|
||||
off_t start_;
|
||||
off_t size_;
|
||||
unsigned char* data_;
|
||||
int lock_count_;
|
||||
};
|
||||
|
||||
friend class File_view;
|
||||
|
||||
View*
|
||||
find_view(off_t start, off_t size);
|
||||
|
||||
off_t
|
||||
do_read(off_t start, off_t size, void* p, off_t* pbytes);
|
||||
|
||||
View*
|
||||
find_or_make_view(off_t start, off_t size, off_t* pbytes);
|
||||
|
||||
void
|
||||
clear_views(bool);
|
||||
|
||||
std::string name_;
|
||||
int descriptor_;
|
||||
int lock_count_;
|
||||
std::list<View*> view_list_;
|
||||
};
|
||||
|
||||
// A view of file data that persists even when the file is unlocked.
|
||||
// Callers should destroy these when no longer required. These are
|
||||
// obtained form File_read::get_lasting_view. They may only be
|
||||
// destroyed when the underlying File_read is locked.
|
||||
|
||||
class File_view
|
||||
{
|
||||
public:
|
||||
// This may only be called when the underlying File_read is locked.
|
||||
~File_view();
|
||||
|
||||
// Return a pointer to the data associated with this view.
|
||||
const unsigned char*
|
||||
data() const
|
||||
{ return this->data_; }
|
||||
|
||||
private:
|
||||
File_view(const File_view&);
|
||||
File_view& operator=(const File_view&);
|
||||
|
||||
friend class File_read;
|
||||
|
||||
// Callers have to get these via File_read::get_lasting_view.
|
||||
File_view(File_read& file, File_read::View* view, const unsigned char* data)
|
||||
: file_(file), view_(view), data_(data)
|
||||
{ }
|
||||
|
||||
File_read& file_;
|
||||
File_read::View* view_;
|
||||
const unsigned char* data_;
|
||||
};
|
||||
|
||||
// An object which locks a file using RAII.
|
||||
|
||||
class File_read_lock
|
||||
{
|
||||
public:
|
||||
File_read_lock(File_read& file)
|
||||
: file_(file)
|
||||
{ this->file_.lock(); }
|
||||
|
||||
~File_read_lock()
|
||||
{ this->file_.unlock(); }
|
||||
|
||||
private:
|
||||
File_read& file_;
|
||||
};
|
||||
|
||||
// All the information we hold for a single input file. This can be
|
||||
// an object file, a shared library, or an archive.
|
||||
|
||||
class Input_file
|
||||
{
|
||||
public:
|
||||
Input_file(const Input_argument& input_argument)
|
||||
: input_argument_(input_argument)
|
||||
{ }
|
||||
|
||||
void
|
||||
open(const General_options&, const Dirsearch&);
|
||||
|
||||
// Return the name given by the user.
|
||||
const char*
|
||||
name() const
|
||||
{ return this->input_argument_.name(); }
|
||||
|
||||
// Return the file name.
|
||||
const std::string&
|
||||
filename() const
|
||||
{ return this->file_.filename(); }
|
||||
|
||||
File_read&
|
||||
file()
|
||||
{ return this->file_; }
|
||||
|
||||
private:
|
||||
const Input_argument& input_argument_;
|
||||
File_read file_;
|
||||
};
|
||||
|
||||
} // end namespace gold
|
||||
|
||||
#endif // !defined(GOLD_FILEREAD_H)
|
|
@ -0,0 +1,230 @@
|
|||
// gold-threads.cc -- thread support for gold
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "gold.h"
|
||||
|
||||
#ifdef ENABLE_THREADS
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#include "gold-threads.h"
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
||||
// Class Lock_impl.
|
||||
|
||||
class Lock_impl
|
||||
{
|
||||
public:
|
||||
Lock_impl();
|
||||
~Lock_impl();
|
||||
|
||||
void acquire();
|
||||
|
||||
void release();
|
||||
|
||||
private:
|
||||
// This class can not be copied.
|
||||
Lock_impl(const Lock_impl&);
|
||||
Lock_impl& operator=(const Lock_impl&);
|
||||
|
||||
friend class Condvar_impl;
|
||||
|
||||
#ifdef ENABLE_THREADS
|
||||
pthread_mutex_t mutex_;
|
||||
#else
|
||||
bool acquired_;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef ENABLE_THREADS
|
||||
|
||||
Lock_impl::Lock_impl()
|
||||
{
|
||||
pthread_mutexattr_t attr;
|
||||
if (pthread_mutexattr_init(&attr) != 0)
|
||||
gold_fatal(_("pthead_mutextattr_init failed"), true);
|
||||
#ifdef PTHREAD_MUTEXT_ADAPTIVE_NP
|
||||
if (pthread_mutextattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP) != 0)
|
||||
gold_fatal(_("pthread_mutextattr_settype failed"), true);
|
||||
#endif
|
||||
|
||||
if (pthread_mutex_init (&this->mutex_, &attr) != 0)
|
||||
gold_fatal(_("pthread_mutex_init failed"), true);
|
||||
|
||||
if (pthread_mutexattr_destroy(&attr) != 0)
|
||||
gold_fatal(_("pthread_mutexattr_destroy failed"), true);
|
||||
}
|
||||
|
||||
Lock_impl::~Lock_impl()
|
||||
{
|
||||
if (pthread_mutex_destroy(&this->mutex_) != 0)
|
||||
gold_fatal(_("pthread_mutex_destroy failed"), true);
|
||||
}
|
||||
|
||||
void
|
||||
Lock_impl::acquire()
|
||||
{
|
||||
if (pthread_mutex_lock(&this->mutex_) != 0)
|
||||
gold_fatal(_("pthread_mutex_lock failed"), true);
|
||||
}
|
||||
|
||||
void
|
||||
Lock_impl::release()
|
||||
{
|
||||
if (pthread_mutex_unlock(&this->mutex_) != 0)
|
||||
gold_fatal(_("pthread_mutex_unlock failed"), true);
|
||||
}
|
||||
|
||||
#else // !defined(ENABLE_THREADS)
|
||||
|
||||
Lock_impl::Lock_impl()
|
||||
: acquired_(false)
|
||||
{
|
||||
}
|
||||
|
||||
Lock_impl::~Lock_impl()
|
||||
{
|
||||
assert(!this->acquired_);
|
||||
}
|
||||
|
||||
void
|
||||
Lock_impl::acquire()
|
||||
{
|
||||
assert(!this->acquired_);
|
||||
this->acquired_ = true;
|
||||
}
|
||||
|
||||
void
|
||||
Lock_impl::release()
|
||||
{
|
||||
assert(this->acquired_);
|
||||
this->acquired_ = false;
|
||||
}
|
||||
|
||||
#endif // !defined(ENABLE_THREADS)
|
||||
|
||||
// Methods for Lock class.
|
||||
|
||||
Lock::Lock()
|
||||
{
|
||||
this->lock_ = new Lock_impl;
|
||||
}
|
||||
|
||||
Lock::~Lock()
|
||||
{
|
||||
delete this->lock_;
|
||||
}
|
||||
|
||||
void
|
||||
Lock::acquire()
|
||||
{
|
||||
this->lock_->acquire();
|
||||
}
|
||||
|
||||
void
|
||||
Lock::release()
|
||||
{
|
||||
this->lock_->release();
|
||||
}
|
||||
|
||||
// Class Condvar_impl.
|
||||
|
||||
class Condvar_impl
|
||||
{
|
||||
public:
|
||||
Condvar_impl();
|
||||
~Condvar_impl();
|
||||
|
||||
void wait(Lock_impl*);
|
||||
void signal();
|
||||
|
||||
private:
|
||||
// This class can not be copied.
|
||||
Condvar_impl(const Condvar_impl&);
|
||||
Condvar_impl& operator=(const Condvar_impl&);
|
||||
|
||||
#ifdef ENABLE_THREADS
|
||||
pthread_cond_t cond_;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef ENABLE_THREADS
|
||||
|
||||
Condvar_impl::Condvar_impl()
|
||||
{
|
||||
if (pthread_cond_init(&this->cond_, NULL) != 0)
|
||||
gold_fatal(_("pthread_cond_init failed"), true);
|
||||
}
|
||||
|
||||
Condvar_impl::~Condvar_impl()
|
||||
{
|
||||
if (pthread_cond_destroy(&this->cond_) != 0)
|
||||
gold_fatal(_("pthread_cond_destroy failed"), true);
|
||||
}
|
||||
|
||||
void
|
||||
Condvar_impl::wait(Lock_impl* li)
|
||||
{
|
||||
if (pthread_cond_wait(&this->cond_, &li->mutex_) != 0)
|
||||
gold_fatal(_("pthread_cond_wait failed"), true);
|
||||
}
|
||||
|
||||
void
|
||||
Condvar_impl::signal()
|
||||
{
|
||||
if (pthread_cond_signal(&this->cond_) != 0)
|
||||
gold_fatal(_("pthread_cond_signal failed"), true);
|
||||
}
|
||||
|
||||
#else // !defined(ENABLE_THREADS)
|
||||
|
||||
Condvar_impl::Condvar_impl()
|
||||
{
|
||||
}
|
||||
|
||||
Condvar_impl::~Condvar_impl()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Condvar_impl::wait(Lock_impl* li)
|
||||
{
|
||||
assert(li->acquired_);
|
||||
}
|
||||
|
||||
void
|
||||
Condvar_impl::signal()
|
||||
{
|
||||
}
|
||||
|
||||
#endif // !defined(ENABLE_THREADS)
|
||||
|
||||
// Methods for Condvar class.
|
||||
|
||||
Condvar::Condvar(Lock& lock)
|
||||
: lock_(lock)
|
||||
{
|
||||
this->condvar_ = new Condvar_impl;
|
||||
}
|
||||
|
||||
Condvar::~Condvar()
|
||||
{
|
||||
delete this->condvar_;
|
||||
}
|
||||
|
||||
void
|
||||
Condvar::wait()
|
||||
{
|
||||
this->condvar_->wait(this->lock_.get_impl());
|
||||
}
|
||||
|
||||
void
|
||||
Condvar::signal()
|
||||
{
|
||||
this->condvar_->signal();
|
||||
}
|
||||
|
||||
} // End namespace gold.
|
|
@ -0,0 +1,101 @@
|
|||
// gold-threads.h -- thread support for gold -*- C++ -*-
|
||||
|
||||
// gold can be configured to support threads. If threads are
|
||||
// supported, the user can specify at runtime whether or not to
|
||||
// support them. This provides an interface to manage locking
|
||||
// accordingly.
|
||||
|
||||
// Lock
|
||||
// A simple lock class.
|
||||
|
||||
#ifndef GOLD_THREADS_H
|
||||
#define GOLD_THREADS_H
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
||||
class Lock_impl;
|
||||
class Condvar;
|
||||
|
||||
// A simple lock class.
|
||||
|
||||
class Lock
|
||||
{
|
||||
public:
|
||||
Lock();
|
||||
~Lock();
|
||||
|
||||
// Acquire the lock.
|
||||
void
|
||||
acquire();
|
||||
|
||||
// Release the lock.
|
||||
void
|
||||
release();
|
||||
|
||||
private:
|
||||
// This class can not be copied.
|
||||
Lock(const Lock&);
|
||||
Lock& operator=(const Lock&);
|
||||
|
||||
friend class Condvar;
|
||||
Lock_impl*
|
||||
get_impl() const
|
||||
{ return this->lock_; }
|
||||
|
||||
Lock_impl* lock_;
|
||||
};
|
||||
|
||||
// RAII for Lock.
|
||||
|
||||
class Hold_lock
|
||||
{
|
||||
public:
|
||||
Hold_lock(Lock& lock)
|
||||
: lock_(lock)
|
||||
{ this->lock_.acquire(); }
|
||||
|
||||
~Hold_lock()
|
||||
{ this->lock_.release(); }
|
||||
|
||||
private:
|
||||
// This class can not be copied.
|
||||
Hold_lock(const Hold_lock&);
|
||||
Hold_lock& operator=(const Hold_lock&);
|
||||
|
||||
Lock& lock_;
|
||||
};
|
||||
|
||||
class Condvar_impl;
|
||||
|
||||
// A simple condition variable class. It is always associated with a
|
||||
// specific lock.
|
||||
|
||||
class Condvar
|
||||
{
|
||||
public:
|
||||
Condvar(Lock& lock);
|
||||
~Condvar();
|
||||
|
||||
// Wait for the condition variable to be signalled. This should
|
||||
// only be called when the lock is held.
|
||||
void
|
||||
wait();
|
||||
|
||||
// Signal the condition variable. This should only be called when
|
||||
// the lock is held.
|
||||
void
|
||||
signal();
|
||||
|
||||
private:
|
||||
// This class can not be copied.
|
||||
Condvar(const Condvar&);
|
||||
Condvar& operator=(const Condvar&);
|
||||
|
||||
Lock& lock_;
|
||||
Condvar_impl* condvar_;
|
||||
};
|
||||
|
||||
} // End namespace gold.
|
||||
|
||||
#endif // !defined(GOLD_THREADS_H)
|
|
@ -0,0 +1,129 @@
|
|||
// ld.c -- linker main function
|
||||
|
||||
#include "gold.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "options.h"
|
||||
#include "workqueue.h"
|
||||
#include "dirsearch.h"
|
||||
#include "readsyms.h"
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
||||
const char* program_name;
|
||||
|
||||
void
|
||||
gold_exit(bool status)
|
||||
{
|
||||
exit(status ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
}
|
||||
|
||||
void
|
||||
gold_fatal(const char* msg, bool perrno)
|
||||
{
|
||||
fprintf(stderr, "%s: ", program_name);
|
||||
if (perrno)
|
||||
perror(msg);
|
||||
else
|
||||
fprintf(stderr, "%s\n", msg);
|
||||
gold_exit(false);
|
||||
}
|
||||
|
||||
void
|
||||
gold_nomem()
|
||||
{
|
||||
// We are out of memory, so try hard to print a reasonable message.
|
||||
// Note that we don't try to translate this message, since the
|
||||
// translation process itself will require memory.
|
||||
write(2, program_name, strlen(program_name));
|
||||
const char* const s = ": out of memory\n";
|
||||
write(2, s, strlen(s));
|
||||
gold_exit(false);
|
||||
}
|
||||
|
||||
void
|
||||
gold_unreachable()
|
||||
{
|
||||
abort();
|
||||
}
|
||||
|
||||
} // End namespace gold.
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
using namespace gold;
|
||||
|
||||
// Queue up the initial set of tasks for this link job.
|
||||
|
||||
void
|
||||
queue_initial_tasks(const General_options& options,
|
||||
const Dirsearch& search_path,
|
||||
const Command_line::Input_argument_list& inputs,
|
||||
Workqueue* workqueue)
|
||||
{
|
||||
if (inputs.empty())
|
||||
gold_fatal(_("no input files"), false);
|
||||
|
||||
// Read the input files. We have to add the symbols to the symbol
|
||||
// table in order. We do this by creating a separate blocker for
|
||||
// each input file. We associate the blocker with the following
|
||||
// input file, to give us a convenient place to delete it.
|
||||
Task_token* this_blocker = NULL;
|
||||
for (Command_line::Input_argument_list::const_iterator p = inputs.begin();
|
||||
p != inputs.end();
|
||||
++p)
|
||||
{
|
||||
Task_token* next_blocker = new Task_token();
|
||||
next_blocker->add_blocker();
|
||||
workqueue->queue(new Read_symbols(options, search_path, *p, this_blocker,
|
||||
next_blocker));
|
||||
this_blocker = next_blocker;
|
||||
}
|
||||
|
||||
// workqueue->queue(new Layout(options, inputs, this_blocker));
|
||||
}
|
||||
|
||||
} // end anonymous namespace.
|
||||
|
||||
int
|
||||
main(int argc, char** argv)
|
||||
{
|
||||
#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
|
||||
setlocale (LC_MESSAGES, "");
|
||||
#endif
|
||||
#if defined (HAVE_SETLOCALE)
|
||||
setlocale (LC_CTYPE, "");
|
||||
#endif
|
||||
bindtextdomain (PACKAGE, LOCALEDIR);
|
||||
textdomain (PACKAGE);
|
||||
|
||||
gold::program_name = argv[0];
|
||||
|
||||
// Handle the command line options.
|
||||
gold::Command_line command_line;
|
||||
command_line.process(argc - 1, argv + 1);
|
||||
|
||||
// The work queue.
|
||||
gold::Workqueue workqueue(command_line.options());
|
||||
|
||||
// The symbol table.
|
||||
|
||||
// Get the search path from the -L options.
|
||||
Dirsearch search_path;
|
||||
search_path.add(&workqueue, command_line.options().search_path());
|
||||
|
||||
// Queue up the first set of tasks.
|
||||
queue_initial_tasks(command_line.options(), search_path,
|
||||
command_line.inputs(), &workqueue);
|
||||
|
||||
// Run the main task processing loop.
|
||||
workqueue.process();
|
||||
|
||||
gold::gold_exit(true);
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
// gold.h -- general definitions for gold -*- C++ -*-
|
||||
|
||||
#ifndef GOLD_GOLD_H
|
||||
|
||||
#include "config.h"
|
||||
#include "ansidecl.h"
|
||||
|
||||
#ifdef ENABLE_NLS
|
||||
# include <libintl.h>
|
||||
# define _(String) gettext (String)
|
||||
# ifdef gettext_noop
|
||||
# define N_(String) gettext_noop (String)
|
||||
# else
|
||||
# define N_(String) (String)
|
||||
# endif
|
||||
#else
|
||||
# define gettext(Msgid) (Msgid)
|
||||
# define dgettext(Domainname, Msgid) (Msgid)
|
||||
# define dcgettext(Domainname, Msgid, Category) (Msgid)
|
||||
# define textdomain(Domainname) while (0) /* nothing */
|
||||
# define bindtextdomain(Domainname, Dirname) while (0) /* nothing */
|
||||
# define _(String) (String)
|
||||
# define N_(String) (String)
|
||||
#endif
|
||||
|
||||
// Figure out how to get a hash set and a hash map. The fallback is
|
||||
// to just use set and map.
|
||||
|
||||
#include <tr1/unordered_set>
|
||||
#include <tr1/unordered_map>
|
||||
|
||||
// We need a template typedef here.
|
||||
|
||||
#define Unordered_set std::tr1::unordered_set
|
||||
#define Unordered_map std::tr1::unordered_map
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
||||
// The name of the program as used in error messages.
|
||||
extern const char* program_name;
|
||||
|
||||
// This function is called to exit the program. Status is true to
|
||||
// exit success (0) and false to exit failure (1).
|
||||
extern void
|
||||
gold_exit(bool status) ATTRIBUTE_NORETURN;
|
||||
|
||||
// This function is called to emit an unexpected error message and a
|
||||
// newline, and then exit with failure. If PERRNO is true, it reports
|
||||
// the error in errno.
|
||||
extern void
|
||||
gold_fatal(const char* msg, bool perrno) ATTRIBUTE_NORETURN;
|
||||
|
||||
// This is function is called in some cases if we run out of memory.
|
||||
extern void
|
||||
gold_nomem() ATTRIBUTE_NORETURN;
|
||||
|
||||
// This function is called in cases which can not arise if the code is
|
||||
// written correctly.
|
||||
extern void
|
||||
gold_unreachable() ATTRIBUTE_NORETURN;
|
||||
|
||||
} // End namespace gold.
|
||||
|
||||
#endif // !defined(GOLD_GOLD_H)
|
|
@ -0,0 +1,381 @@
|
|||
// object.cc -- support for an object file for linking in gold
|
||||
|
||||
#include "gold.h"
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
|
||||
#include "object.h"
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
||||
// Class Object.
|
||||
|
||||
const unsigned char*
|
||||
Object::get_view(off_t start, off_t size)
|
||||
{
|
||||
return this->input_file_->file().get_view(start + this->offset_, size);
|
||||
}
|
||||
|
||||
void
|
||||
Object::read(off_t start, off_t size, void* p)
|
||||
{
|
||||
this->input_file_->file().read(start + this->offset_, size, p);
|
||||
}
|
||||
|
||||
File_view*
|
||||
Object::get_lasting_view(off_t start, off_t size)
|
||||
{
|
||||
return this->input_file_->file().get_lasting_view(start + this->offset_,
|
||||
size);
|
||||
}
|
||||
|
||||
// Class Sized_object.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
Sized_object<size, big_endian>::Sized_object(
|
||||
const std::string& name,
|
||||
Input_file* input_file,
|
||||
off_t offset,
|
||||
const elfcpp::Ehdr<size, big_endian>& ehdr)
|
||||
: Object(name, input_file, offset),
|
||||
osabi_(ehdr.get_e_ident()[elfcpp::EI_OSABI]),
|
||||
abiversion_(ehdr.get_e_ident()[elfcpp::EI_ABIVERSION]),
|
||||
machine_(ehdr.get_e_machine()),
|
||||
flags_(ehdr.get_e_flags()),
|
||||
target_(NULL),
|
||||
shoff_(ehdr.get_e_shoff()),
|
||||
shnum_(0),
|
||||
shstrndx_(0),
|
||||
symtab_shnum_(0)
|
||||
{
|
||||
if (ehdr.get_e_ehsize() != elfcpp::Elf_sizes<size>::ehdr_size)
|
||||
{
|
||||
fprintf(stderr, _("%s: %s: bad e_ehsize field (%d != %d)\n"),
|
||||
program_name, this->name().c_str(), ehdr.get_e_ehsize(),
|
||||
elfcpp::Elf_sizes<size>::ehdr_size);
|
||||
gold_exit(false);
|
||||
}
|
||||
if (ehdr.get_e_shentsize() != elfcpp::Elf_sizes<size>::shdr_size)
|
||||
{
|
||||
fprintf(stderr, _("%s: %s: bad e_shentsize field (%d != %d)\n"),
|
||||
program_name, this->name().c_str(), ehdr.get_e_shentsize(),
|
||||
elfcpp::Elf_sizes<size>::shdr_size);
|
||||
gold_exit(false);
|
||||
}
|
||||
}
|
||||
|
||||
template<int size, bool big_endian>
|
||||
Sized_object<size, big_endian>::~Sized_object()
|
||||
{
|
||||
}
|
||||
|
||||
// Set up an object file bsaed on the file header. This sets up the
|
||||
// target and reads the section information.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
Sized_object<size, big_endian>::setup(
|
||||
const elfcpp::Ehdr<size, big_endian>& ehdr)
|
||||
{
|
||||
// this->target_ = select_target(this->machine_, size, big_endian,
|
||||
// this->osabi_, this->abiversion_);
|
||||
unsigned int shnum = ehdr.get_e_shnum();
|
||||
unsigned int shstrndx = ehdr.get_e_shstrndx();
|
||||
if ((shnum == 0 || shstrndx == elfcpp::SHN_XINDEX)
|
||||
&& this->shoff_ != 0)
|
||||
{
|
||||
const unsigned char* p = this->get_view
|
||||
(this->shoff_, elfcpp::Elf_sizes<size>::shdr_size);
|
||||
elfcpp::Shdr<size, big_endian> shdr(p);
|
||||
if (shnum == 0)
|
||||
shnum = shdr.get_sh_size();
|
||||
if (shstrndx == elfcpp::SHN_XINDEX)
|
||||
shstrndx = shdr.get_sh_link();
|
||||
}
|
||||
this->shnum_ = shnum;
|
||||
this->shstrndx_ = shstrndx;
|
||||
|
||||
if (shnum == 0)
|
||||
return;
|
||||
|
||||
// Find the SHT_SYMTAB section.
|
||||
const unsigned char* p = this->get_view
|
||||
(this->shoff_, shnum * elfcpp::Elf_sizes<size>::shdr_size);
|
||||
// Skip the first section, which is always empty.
|
||||
p += elfcpp::Elf_sizes<size>::shdr_size;
|
||||
for (unsigned int i = 1; i < shnum; ++i)
|
||||
{
|
||||
elfcpp::Shdr<size, big_endian> shdr(p);
|
||||
if (shdr.get_sh_type() == elfcpp::SHT_SYMTAB)
|
||||
{
|
||||
this->symtab_shnum_ = i;
|
||||
break;
|
||||
}
|
||||
p += elfcpp::Elf_sizes<size>::shdr_size;
|
||||
}
|
||||
}
|
||||
|
||||
// Read the symbols and relocations from an object file.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
Read_symbols_data
|
||||
Sized_object<size, big_endian>::do_read_symbols()
|
||||
{
|
||||
if (this->symtab_shnum_ == 0)
|
||||
{
|
||||
// No symbol table. Weird but legal.
|
||||
Read_symbols_data ret;
|
||||
ret.symbols = NULL;
|
||||
ret.symbols_size = 0;
|
||||
ret.symbol_names = NULL;
|
||||
ret.symbol_names_size = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int shdr_size = elfcpp::Elf_sizes<size>::shdr_size;
|
||||
|
||||
// Read the symbol table section header.
|
||||
off_t symtabshdroff = this->shoff_ + (this->symtab_shnum_ * shdr_size);
|
||||
const unsigned char* psymtabshdr = this->get_view(symtabshdroff, shdr_size);
|
||||
elfcpp::Shdr<size, big_endian> symtabshdr(psymtabshdr);
|
||||
assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
|
||||
|
||||
// Read the symbol table.
|
||||
File_view* fvsymtab = this->get_lasting_view(symtabshdr.get_sh_offset(),
|
||||
symtabshdr.get_sh_size());
|
||||
|
||||
// Read the section header for the symbol names.
|
||||
unsigned int strtab_shnum = symtabshdr.get_sh_link();
|
||||
if (strtab_shnum == 0 || strtab_shnum >= this->shnum_)
|
||||
{
|
||||
fprintf(stderr, _("%s: %s: invalid symbol table name index: %u\n"),
|
||||
program_name, this->name().c_str(), strtab_shnum);
|
||||
gold_exit(false);
|
||||
}
|
||||
off_t strtabshdroff = this->shoff_ + (strtab_shnum * shdr_size);
|
||||
const unsigned char *pstrtabshdr = this->get_view(strtabshdroff, shdr_size);
|
||||
elfcpp::Shdr<size, big_endian> strtabshdr(pstrtabshdr);
|
||||
if (strtabshdr.get_sh_type() != elfcpp::SHT_STRTAB)
|
||||
{
|
||||
fprintf(stderr,
|
||||
_("%s: %s: symbol table name section has wrong type: %u\n"),
|
||||
program_name, this->name().c_str(),
|
||||
static_cast<unsigned int>(strtabshdr.get_sh_type()));
|
||||
gold_exit(false);
|
||||
}
|
||||
|
||||
// Read the symbol names.
|
||||
File_view* fvstrtab = this->get_lasting_view(strtabshdr.get_sh_offset(),
|
||||
strtabshdr.get_sh_size());
|
||||
|
||||
Read_symbols_data ret;
|
||||
ret.symbols = fvsymtab;
|
||||
ret.symbols_size = symtabshdr.get_sh_size();
|
||||
ret.symbol_names = fvstrtab;
|
||||
ret.symbol_names_size = strtabshdr.get_sh_size();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Add the symbols to the symbol table.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
Sized_object<size, big_endian>::do_add_symbols(Read_symbols_data sd)
|
||||
{
|
||||
if (sd.symbols == NULL)
|
||||
{
|
||||
assert(sd.symbol_names == NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
int sym_size = elfcpp::Elf_sizes<size>::sym_size;
|
||||
const unsigned char* symstart = sd.symbols->data();
|
||||
const unsigned char* symend = symstart + sd.symbols_size;
|
||||
for (const unsigned char* p = symstart; p < symend; p += sym_size)
|
||||
{
|
||||
elfcpp::Sym<size, big_endian> sym(p);
|
||||
|
||||
unsigned int nameoff = sym.get_st_name();
|
||||
if (nameoff >= sd.symbol_names_size)
|
||||
{
|
||||
fprintf(stderr,
|
||||
_("%s: %s: invalid symbol name offset %u for symbol %d\n"),
|
||||
program_name, this->name().c_str(), nameoff,
|
||||
(p - symstart) / sym_size);
|
||||
gold_exit(false);
|
||||
}
|
||||
const unsigned char* name = sd.symbol_names->data() + nameoff;
|
||||
printf("%s\n", name);
|
||||
}
|
||||
}
|
||||
|
||||
} // End namespace gold.
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
using namespace gold;
|
||||
|
||||
// Read an ELF file with the header and return the appropriate
|
||||
// instance of Object.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
Object*
|
||||
make_elf_sized_object(const std::string& name, Input_file* input_file,
|
||||
off_t offset, const elfcpp::Ehdr<size, big_endian>& ehdr)
|
||||
{
|
||||
int et = ehdr.get_e_type();
|
||||
if (et != elfcpp::ET_REL && et != elfcpp::ET_DYN)
|
||||
{
|
||||
fprintf(stderr, "%s: %s: unsupported ELF type %d\n",
|
||||
program_name, name.c_str(), static_cast<int>(et));
|
||||
gold_exit(false);
|
||||
}
|
||||
|
||||
if (et == elfcpp::ET_REL)
|
||||
{
|
||||
Sized_object<size, big_endian>* obj =
|
||||
new Sized_object<size, big_endian>(name, input_file, offset, ehdr);
|
||||
obj->setup(ehdr);
|
||||
return obj;
|
||||
}
|
||||
else
|
||||
{
|
||||
// elfcpp::ET_DYN
|
||||
fprintf(stderr, _("%s: %s: dynamic objects are not yet supported\n"),
|
||||
program_name, name.c_str());
|
||||
gold_exit(false);
|
||||
// Sized_dynobj<size, big_endian>* obj =
|
||||
// new Sized_dynobj<size, big_endian>(this->input_.name(), input_file,
|
||||
// offset, ehdr);
|
||||
// obj->setup(ehdr);
|
||||
// return obj;
|
||||
}
|
||||
}
|
||||
|
||||
} // End anonymous namespace.
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
||||
// Read an ELF file and return the appropriate instance of Object.
|
||||
|
||||
Object*
|
||||
make_elf_object(const std::string& name, Input_file* input_file, off_t offset,
|
||||
const unsigned char* p, off_t bytes)
|
||||
{
|
||||
if (bytes < elfcpp::EI_NIDENT)
|
||||
{
|
||||
fprintf(stderr, _("%s: %s: ELF file too short\n"),
|
||||
program_name, name.c_str());
|
||||
gold_exit(false);
|
||||
}
|
||||
|
||||
int v = p[elfcpp::EI_VERSION];
|
||||
if (v != elfcpp::EV_CURRENT)
|
||||
{
|
||||
if (v == elfcpp::EV_NONE)
|
||||
fprintf(stderr, _("%s: %s: invalid ELF version 0\n"),
|
||||
program_name, name.c_str());
|
||||
else
|
||||
fprintf(stderr, _("%s: %s: unsupported ELF version %d\n"),
|
||||
program_name, name.c_str(), v);
|
||||
gold_exit(false);
|
||||
}
|
||||
|
||||
int c = p[elfcpp::EI_CLASS];
|
||||
if (c == elfcpp::ELFCLASSNONE)
|
||||
{
|
||||
fprintf(stderr, _("%s: %s: invalid ELF class 0\n"),
|
||||
program_name, name.c_str());
|
||||
gold_exit(false);
|
||||
}
|
||||
else if (c != elfcpp::ELFCLASS32
|
||||
&& c != elfcpp::ELFCLASS64)
|
||||
{
|
||||
fprintf(stderr, _("%s: %s: unsupported ELF class %d\n"),
|
||||
program_name, name.c_str(), c);
|
||||
gold_exit(false);
|
||||
}
|
||||
|
||||
int d = p[elfcpp::EI_DATA];
|
||||
if (d == elfcpp::ELFDATANONE)
|
||||
{
|
||||
fprintf(stderr, _("%s: %s: invalid ELF data encoding\n"),
|
||||
program_name, name.c_str());
|
||||
gold_exit(false);
|
||||
}
|
||||
else if (d != elfcpp::ELFDATA2LSB
|
||||
&& d != elfcpp::ELFDATA2MSB)
|
||||
{
|
||||
fprintf(stderr, _("%s: %s: unsupported ELF data encoding %d\n"),
|
||||
program_name, name.c_str(), d);
|
||||
gold_exit(false);
|
||||
}
|
||||
|
||||
bool big_endian = d == elfcpp::ELFDATA2MSB;
|
||||
|
||||
if (c == elfcpp::ELFCLASS32)
|
||||
{
|
||||
if (bytes < elfcpp::Elf_sizes<32>::ehdr_size)
|
||||
{
|
||||
fprintf(stderr, _("%s: %s: ELF file too short\n"),
|
||||
program_name, name.c_str());
|
||||
gold_exit(false);
|
||||
}
|
||||
if (big_endian)
|
||||
{
|
||||
elfcpp::Ehdr<32, true> ehdr(p);
|
||||
return make_elf_sized_object<32, true>(name, input_file,
|
||||
offset, ehdr);
|
||||
}
|
||||
else
|
||||
{
|
||||
elfcpp::Ehdr<32, false> ehdr(p);
|
||||
return make_elf_sized_object<32, false>(name, input_file,
|
||||
offset, ehdr);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bytes < elfcpp::Elf_sizes<32>::ehdr_size)
|
||||
{
|
||||
fprintf(stderr, _("%s: %s: ELF file too short\n"),
|
||||
program_name, name.c_str());
|
||||
gold_exit(false);
|
||||
}
|
||||
if (big_endian)
|
||||
{
|
||||
elfcpp::Ehdr<64, true> ehdr(p);
|
||||
return make_elf_sized_object<64, true>(name, input_file,
|
||||
offset, ehdr);
|
||||
}
|
||||
else
|
||||
{
|
||||
elfcpp::Ehdr<64, false> ehdr(p);
|
||||
return make_elf_sized_object<64, false>(name, input_file,
|
||||
offset, ehdr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Instantiate the templates we need. We could use the configure
|
||||
// script to restrict this to only the ones for implemented targets.
|
||||
|
||||
template
|
||||
class Sized_object<32, false>;
|
||||
|
||||
template
|
||||
class Sized_object<32, true>;
|
||||
|
||||
template
|
||||
class Sized_object<64, false>;
|
||||
|
||||
template
|
||||
class Sized_object<64, true>;
|
||||
|
||||
} // End namespace gold.
|
|
@ -0,0 +1,160 @@
|
|||
// object.h -- support for an object file for linking in gold -*- C++ -*-
|
||||
|
||||
#ifndef GOLD_OBJECT_H
|
||||
#define GOLD_OBJECT_H
|
||||
|
||||
#include "elfcpp.h"
|
||||
#include "targetsize.h"
|
||||
#include "target.h"
|
||||
#include "fileread.h"
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
||||
// Data to pass from read_symbols() to add_symbols().
|
||||
|
||||
struct Read_symbols_data
|
||||
{
|
||||
// Symbol data.
|
||||
File_view* symbols;
|
||||
// Size of symbol data in bytes.
|
||||
off_t symbols_size;
|
||||
// Symbol names.
|
||||
File_view* symbol_names;
|
||||
// Size of symbol name data in bytes.
|
||||
off_t symbol_names_size;
|
||||
};
|
||||
|
||||
// Object is an interface which represents either a 32-bit or a 64-bit
|
||||
// object file. The actual instantiations are Sized_object<32> and
|
||||
// Sized_object<64>
|
||||
|
||||
class Object
|
||||
{
|
||||
public:
|
||||
// NAME is the name of the object as we would report it to the user
|
||||
// (e.g., libfoo.a(bar.o) if this is in an archive. INPUT_FILE is
|
||||
// used to read the file. OFFSET is the offset within the input
|
||||
// file--0 for a .o or .so file, something else for a .a file.
|
||||
Object(const std::string& name, Input_file* input_file, off_t offset = 0)
|
||||
: name_(name), input_file_(input_file), offset_(offset)
|
||||
{ }
|
||||
|
||||
virtual ~Object()
|
||||
{ }
|
||||
|
||||
const std::string&
|
||||
name() const
|
||||
{ return this->name_; }
|
||||
|
||||
// Read the symbol and relocation information.
|
||||
Read_symbols_data
|
||||
read_symbols()
|
||||
{ return this->do_read_symbols(); }
|
||||
|
||||
// Add symbol information to the global symbol table.
|
||||
void
|
||||
add_symbols(Read_symbols_data rd)
|
||||
{ this->do_add_symbols(rd); }
|
||||
|
||||
protected:
|
||||
// Read the symbols--implemented by child class.
|
||||
virtual Read_symbols_data
|
||||
do_read_symbols() = 0;
|
||||
|
||||
// Add symbol information to the global symbol table--implemented by
|
||||
// child class.
|
||||
virtual void
|
||||
do_add_symbols(Read_symbols_data) = 0;
|
||||
|
||||
// Get the file.
|
||||
Input_file*
|
||||
input_file() const
|
||||
{ return this->input_file_; }
|
||||
|
||||
// Get the offset into the file.
|
||||
off_t
|
||||
offset() const
|
||||
{ return this->offset_; }
|
||||
|
||||
// Get a view into the underlying file.
|
||||
const unsigned char*
|
||||
get_view(off_t start, off_t size);
|
||||
|
||||
// Read data from the underlying file.
|
||||
void
|
||||
read(off_t start, off_t size, void* p);
|
||||
|
||||
// Get a lasting view into the underlying file.
|
||||
File_view*
|
||||
get_lasting_view(off_t start, off_t size);
|
||||
|
||||
private:
|
||||
// This class may not be copied.
|
||||
Object(const Object&);
|
||||
Object& operator=(const Object&);
|
||||
|
||||
// Name of object as printed to use.
|
||||
std::string name_;
|
||||
// For reading the file.
|
||||
Input_file* input_file_;
|
||||
// Offset within the file--0 for an object file, non-0 for an
|
||||
// archive.
|
||||
off_t offset_;
|
||||
};
|
||||
|
||||
// The functions of Object which are size specific.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
class Sized_object : public Object
|
||||
{
|
||||
public:
|
||||
Sized_object(const std::string& name, Input_file* input_file, off_t offset,
|
||||
const typename elfcpp::Ehdr<size, big_endian>&);
|
||||
|
||||
~Sized_object();
|
||||
|
||||
void
|
||||
setup(const typename elfcpp::Ehdr<size, big_endian>&);
|
||||
|
||||
Read_symbols_data
|
||||
do_read_symbols();
|
||||
|
||||
void
|
||||
do_add_symbols(Read_symbols_data);
|
||||
|
||||
private:
|
||||
// This object may not be copied.
|
||||
Sized_object(const Sized_object&);
|
||||
Sized_object& operator=(const Sized_object&);
|
||||
|
||||
// ELF file header EI_OSABI field.
|
||||
unsigned char osabi_;
|
||||
// ELF file header EI_ABIVERSION field.
|
||||
unsigned char abiversion_;
|
||||
// ELF file header e_machine field.
|
||||
elfcpp::Elf_Half machine_;
|
||||
// ELF file header e_flags field.
|
||||
unsigned int flags_;
|
||||
// Target functions--may be NULL.
|
||||
Target* target_;
|
||||
// File offset of section header table.
|
||||
off_t shoff_;
|
||||
// Number of input sections.
|
||||
unsigned int shnum_;
|
||||
// Offset of SHT_STRTAB section holding section names.
|
||||
unsigned int shstrndx_;
|
||||
// Index of SHT_SYMTAB section.
|
||||
unsigned int symtab_shnum_;
|
||||
};
|
||||
|
||||
// Return an Object appropriate for the input file. P is BYTES long,
|
||||
// and holds the ELF header.
|
||||
|
||||
extern Object* make_elf_object(const std::string& name, Input_file*,
|
||||
off_t offset, const unsigned char* p,
|
||||
off_t bytes);
|
||||
|
||||
} // end namespace gold
|
||||
|
||||
#endif // !defined(GOLD_OBJECT_H)
|
|
@ -0,0 +1,414 @@
|
|||
// options.c -- handle command line options for gold
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "gold.h"
|
||||
#include "options.h"
|
||||
|
||||
// The information we keep for a single command line option.
|
||||
|
||||
struct gold::options::One_option
|
||||
{
|
||||
// The single character option name, or '\0' if this is only a long
|
||||
// option.
|
||||
char short_option;
|
||||
|
||||
// The long option name, or NULL if this is only a short option.
|
||||
const char* long_option;
|
||||
|
||||
// Description of the option for --help output, or NULL if there is none.
|
||||
const char* doc;
|
||||
|
||||
// How to print the option name in --help output, or NULL to use the
|
||||
// default.
|
||||
const char* help_output;
|
||||
|
||||
// Long option dash control. This is ignored if long_option is
|
||||
// NULL.
|
||||
enum
|
||||
{
|
||||
// Long option normally takes one dash; two dashes are also
|
||||
// accepted.
|
||||
ONE_DASH,
|
||||
// Long option normally takes two dashes; one dash is also
|
||||
// accepted.
|
||||
TWO_DASHES,
|
||||
// Long option always takes two dashes.
|
||||
EXACTLY_TWO_DASHES
|
||||
} dash;
|
||||
|
||||
// Function for special handling, or NULL. Returns the number of
|
||||
// arguments to skip. This will normally be at least 1, but it may
|
||||
// be 0 if this function changes *argv. ARG points to the location
|
||||
// in *ARGV where the option starts, which may be helpful for a
|
||||
// short option.
|
||||
int (*special)(int argc, char** argv, char *arg, gold::Command_line*);
|
||||
|
||||
// If this is a position independent option which does not take an
|
||||
// argument, this is the member function to call to record it.
|
||||
void (gold::General_options::*general_noarg)();
|
||||
|
||||
// If this is a position independent function which takes an
|
||||
// argument, this is the member function to call to record it.
|
||||
void (gold::General_options::*general_arg)(const char*);
|
||||
|
||||
// If this is a position dependent option which does not take an
|
||||
// argument, this is the member function to call to record it.
|
||||
void (gold::Position_dependent_options::*dependent_noarg)();
|
||||
|
||||
// If this is a position dependent option which takes an argument,
|
||||
// this is the member function to record it.
|
||||
void (gold::Position_dependent_options::*dependent_arg)(const char*);
|
||||
|
||||
// Return whether this option takes an argument.
|
||||
bool
|
||||
takes_argument() const
|
||||
{ return this->general_arg != NULL || this->dependent_arg != NULL; }
|
||||
};
|
||||
|
||||
class gold::options::Command_line_options
|
||||
{
|
||||
public:
|
||||
static const One_option options[];
|
||||
static const int options_size;
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
// Report usage information for ld --help, and exit.
|
||||
|
||||
int
|
||||
help(int, char**, char*, gold::Command_line*)
|
||||
{
|
||||
printf(_("Usage: %s [options] file...\nOptions:\n"), gold::program_name);
|
||||
|
||||
const int options_size = gold::options::Command_line_options::options_size;
|
||||
const gold::options::One_option* options =
|
||||
gold::options::Command_line_options::options;
|
||||
for (int i = 0; i < options_size; ++i)
|
||||
{
|
||||
if (options[i].doc == NULL)
|
||||
continue;
|
||||
|
||||
printf(" ");
|
||||
int len = 2;
|
||||
bool comma = false;
|
||||
|
||||
int j = i;
|
||||
do
|
||||
{
|
||||
if (options[j].help_output != NULL)
|
||||
{
|
||||
if (comma)
|
||||
{
|
||||
printf(", ");
|
||||
len += 2;
|
||||
}
|
||||
printf(options[j].help_output);
|
||||
len += std::strlen(options[i].help_output);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (options[j].short_option != '\0')
|
||||
{
|
||||
if (comma)
|
||||
{
|
||||
printf(", ");
|
||||
len += 2;
|
||||
}
|
||||
printf("-%c", options[j].short_option);
|
||||
len += 2;
|
||||
}
|
||||
|
||||
if (options[j].long_option != NULL)
|
||||
{
|
||||
if (comma)
|
||||
{
|
||||
printf(", ");
|
||||
len += 2;
|
||||
}
|
||||
if (options[j].dash == gold::options::One_option::ONE_DASH)
|
||||
{
|
||||
printf("-");
|
||||
++len;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("--");
|
||||
len += 2;
|
||||
}
|
||||
printf("%s", options[j].long_option);
|
||||
len += std::strlen(options[j].long_option);
|
||||
}
|
||||
}
|
||||
++j;
|
||||
}
|
||||
while (j < options_size && options[j].doc == NULL);
|
||||
|
||||
if (len > 30)
|
||||
{
|
||||
printf("\n");
|
||||
len = 0;
|
||||
}
|
||||
for (; len < 30; ++len)
|
||||
std::putchar(' ');
|
||||
|
||||
std::puts(options[i].doc);
|
||||
}
|
||||
|
||||
gold::gold_exit(true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // End empty namespace.
|
||||
|
||||
// Helper macros used to specify the options. We could also do this
|
||||
// using constructors, but then g++ would generate code to initialize
|
||||
// the array. We want the array to be initialized statically so that
|
||||
// we get better startup time.
|
||||
|
||||
#define GENERAL_NOARG(short_option, long_option, doc, help, dash, func) \
|
||||
{ short_option, long_option, doc, help, gold::options::One_option::dash, \
|
||||
NULL, func, NULL, NULL, NULL }
|
||||
#define GENERAL_ARG(short_option, long_option, doc, help, dash, func) \
|
||||
{ short_option, long_option, doc, help, gold::options::One_option::dash, \
|
||||
NULL, NULL, func, NULL, NULL }
|
||||
#define POSDEP_NOARG(short_option, long_option, doc, help, dash, func) \
|
||||
{ short_option, long_option, doc, help, gold::options::One_option::dash, \
|
||||
NULL, NULL, NULL, func, NULL }
|
||||
#define POSDEP_ARG(short_option, long_option, doc, help, dash, func) \
|
||||
{ short_option, long_option, doc, help, gold::options::One_option::dash, \
|
||||
NULL, NULL, NULL, NULL, func }
|
||||
#define SPECIAL(short_option, long_option, doc, help, dash, func) \
|
||||
{ short_option, long_option, doc, help, gold::options::One_option::dash, \
|
||||
func, NULL, NULL, NULL, NULL }
|
||||
|
||||
// Here is the actual list of options which we accept.
|
||||
|
||||
const gold::options::One_option
|
||||
gold::options::Command_line_options::options[] =
|
||||
{
|
||||
GENERAL_ARG('L', "library-path", N_("Add directory to search path"),
|
||||
N_("-L DIR, --library-path DIR"), TWO_DASHES,
|
||||
&gold::General_options::add_to_search_path),
|
||||
GENERAL_NOARG('r', NULL, N_("Generate relocatable output"), NULL,
|
||||
ONE_DASH, &gold::General_options::set_relocatable),
|
||||
GENERAL_NOARG('\0', "static", N_("Do not link against shared libraries"),
|
||||
NULL, ONE_DASH, &gold::General_options::set_static),
|
||||
SPECIAL('\0', "help", N_("Report usage information"), NULL,
|
||||
TWO_DASHES, &help)
|
||||
};
|
||||
|
||||
const int gold::options::Command_line_options::options_size =
|
||||
sizeof (options) / sizeof (options[0]);
|
||||
|
||||
// The default values for the general options.
|
||||
|
||||
gold::General_options::General_options()
|
||||
: is_relocatable_(false)
|
||||
{
|
||||
}
|
||||
|
||||
// The default values for the position dependent options.
|
||||
|
||||
gold::Position_dependent_options::Position_dependent_options()
|
||||
: do_static_search_(false)
|
||||
{
|
||||
}
|
||||
|
||||
// Construct a Command_line.
|
||||
|
||||
gold::Command_line::Command_line()
|
||||
{
|
||||
}
|
||||
|
||||
// Process the command line options.
|
||||
|
||||
void
|
||||
gold::Command_line::process(int argc, char** argv)
|
||||
{
|
||||
const int options_size = gold::options::Command_line_options::options_size;
|
||||
const gold::options::One_option* options =
|
||||
gold::options::Command_line_options::options;
|
||||
bool no_more_options = false;
|
||||
int i = 0;
|
||||
while (i < argc)
|
||||
{
|
||||
if (argv[i][0] != '-' || no_more_options)
|
||||
{
|
||||
this->inputs_.push_back(Input_argument(argv[i],
|
||||
this->position_options_));
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Option starting with '-'.
|
||||
int dashes = 1;
|
||||
if (argv[i][1] == '-')
|
||||
{
|
||||
dashes = 2;
|
||||
if (argv[i][2] == '\0')
|
||||
{
|
||||
no_more_options = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Look for a long option match.
|
||||
char* opt = argv[i] + dashes;
|
||||
char first = opt[0];
|
||||
int skiparg = 0;
|
||||
char* arg = strchr(opt, '=');
|
||||
if (arg != NULL)
|
||||
*arg = '\0';
|
||||
else if (i + 1 < argc)
|
||||
{
|
||||
arg = argv[i + 1];
|
||||
skiparg = 1;
|
||||
}
|
||||
|
||||
int j;
|
||||
for (j = 0; j < options_size; ++j)
|
||||
{
|
||||
if (options[j].long_option != NULL
|
||||
&& (dashes == 2
|
||||
|| (options[j].dash
|
||||
!= gold::options::One_option::EXACTLY_TWO_DASHES))
|
||||
&& first == options[j].long_option[0]
|
||||
&& strcmp(opt, options[j].long_option) == 0)
|
||||
{
|
||||
if (options[j].special)
|
||||
i += options[j].special(argc - 1, argv + i, opt, this);
|
||||
else
|
||||
{
|
||||
if (!options[j].takes_argument())
|
||||
{
|
||||
arg = NULL;
|
||||
skiparg = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (arg == NULL)
|
||||
this->usage(_("missing argument"), argv[i]);
|
||||
}
|
||||
this->apply_option(options[j], arg);
|
||||
i += skiparg + 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j < options_size)
|
||||
continue;
|
||||
|
||||
// If we saw two dashes, we need to see a long option.
|
||||
if (dashes == 2)
|
||||
this->usage(_("unknown option"), argv[i]);
|
||||
|
||||
// Look for a short option match. There may be more than one
|
||||
// short option in a given argument.
|
||||
bool done = false;
|
||||
char* s = argv[i] + 1;
|
||||
++i;
|
||||
while (*s != '\0' && !done)
|
||||
{
|
||||
char opt = *s;
|
||||
int j;
|
||||
for (j = 0; j < options_size; ++j)
|
||||
{
|
||||
if (options[j].short_option == opt)
|
||||
{
|
||||
if (options[j].special)
|
||||
{
|
||||
// Undo the argument skip done above.
|
||||
--i;
|
||||
i += options[j].special(argc - i, argv + i, s, this);
|
||||
done = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
arg = NULL;
|
||||
if (options[j].takes_argument())
|
||||
{
|
||||
if (s[1] != '\0')
|
||||
{
|
||||
arg = s + 1;
|
||||
done = true;
|
||||
}
|
||||
else if (i < argc)
|
||||
{
|
||||
arg = argv[i];
|
||||
++i;
|
||||
}
|
||||
else
|
||||
this->usage(_("missing argument"), opt);
|
||||
}
|
||||
this->apply_option(options[j], arg);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (j >= options_size)
|
||||
this->usage(_("unknown option"), *s);
|
||||
|
||||
++s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Apply a command line option.
|
||||
|
||||
void
|
||||
gold::Command_line::apply_option(const gold::options::One_option& opt,
|
||||
const char* arg)
|
||||
{
|
||||
if (arg == NULL)
|
||||
{
|
||||
if (opt.general_noarg)
|
||||
(this->options_.*(opt.general_noarg))();
|
||||
else if (opt.dependent_noarg)
|
||||
(this->position_options_.*(opt.dependent_noarg))();
|
||||
else
|
||||
gold::gold_unreachable();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (opt.general_arg)
|
||||
(this->options_.*(opt.general_arg))(arg);
|
||||
else if (opt.dependent_arg)
|
||||
(this->position_options_.*(opt.dependent_arg))(arg);
|
||||
else
|
||||
gold::gold_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
// Report a usage error. */
|
||||
|
||||
void
|
||||
gold::Command_line::usage()
|
||||
{
|
||||
fprintf(stderr,
|
||||
_("%s: use the --help option for usage information\n"),
|
||||
gold::program_name);
|
||||
gold::gold_exit(false);
|
||||
}
|
||||
|
||||
void
|
||||
gold::Command_line::usage(const char* msg, const char *opt)
|
||||
{
|
||||
fprintf(stderr,
|
||||
_("%s: %s: %s\n"),
|
||||
gold::program_name, opt, msg);
|
||||
this->usage();
|
||||
}
|
||||
|
||||
void
|
||||
gold::Command_line::usage(const char* msg, char opt)
|
||||
{
|
||||
fprintf(stderr,
|
||||
_("%s: -%c: %s\n"),
|
||||
gold::program_name, opt, msg);
|
||||
this->usage();
|
||||
}
|
|
@ -0,0 +1,174 @@
|
|||
// options.h -- handle command line options for gold -*- C++ -*-
|
||||
|
||||
// Command_line
|
||||
// Holds everything we get from the command line.
|
||||
// General_options (from Command_line::options())
|
||||
// Options which are not position dependent.
|
||||
// Input_argument (from Command_line::inputs())
|
||||
// The list of input files, including -l options.
|
||||
// Position_dependent_options (from Input_argument::options())
|
||||
// Position dependent options which apply to this argument.
|
||||
|
||||
#ifndef GOLD_OPTIONS_H
|
||||
#define GOLD_OPTIONS_H
|
||||
|
||||
#include <list>
|
||||
|
||||
#include "gold.h"
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
||||
class Command_line;
|
||||
|
||||
namespace options {
|
||||
|
||||
class Command_line_options;
|
||||
struct One_option;
|
||||
|
||||
} // End namespace gold::options.
|
||||
|
||||
// The position independent options which apply to the whole link.
|
||||
// There are a lot of them.
|
||||
|
||||
class General_options
|
||||
{
|
||||
public:
|
||||
General_options();
|
||||
|
||||
// -L: Library search path.
|
||||
typedef std::list<const char*> Dir_list;
|
||||
|
||||
const Dir_list&
|
||||
search_path() const
|
||||
{ return this->search_path_; }
|
||||
|
||||
// -r: Whether we are doing a relocatable link.
|
||||
bool
|
||||
is_relocatable() const
|
||||
{ return this->is_relocatable_; }
|
||||
|
||||
// --static: Whether doing a static link.
|
||||
bool
|
||||
is_static() const
|
||||
{ return this->is_static_; }
|
||||
|
||||
private:
|
||||
friend class Command_line;
|
||||
friend class options::Command_line_options;
|
||||
|
||||
void
|
||||
add_to_search_path(const char* arg)
|
||||
{ this->search_path_.push_back(arg); }
|
||||
|
||||
void
|
||||
set_relocatable()
|
||||
{ this->is_relocatable_ = true; }
|
||||
|
||||
void
|
||||
set_static()
|
||||
{ this->is_static_ = true; }
|
||||
|
||||
Dir_list search_path_;
|
||||
bool is_relocatable_;
|
||||
bool is_static_;
|
||||
|
||||
// Don't copy this structure.
|
||||
General_options(const General_options&);
|
||||
General_options& operator=(const General_options&);
|
||||
};
|
||||
|
||||
// The current state of the position dependent options.
|
||||
|
||||
class Position_dependent_options
|
||||
{
|
||||
public:
|
||||
Position_dependent_options();
|
||||
|
||||
// -Bstatic: Whether we are searching for a static archive rather
|
||||
// -than a shared object.
|
||||
bool
|
||||
do_static_search()
|
||||
{ return this->do_static_search_; }
|
||||
|
||||
private:
|
||||
friend class Command_line;
|
||||
friend class options::Command_line_options;
|
||||
|
||||
void
|
||||
set_static_search()
|
||||
{ this->do_static_search_ = true; }
|
||||
|
||||
void
|
||||
set_dynamic_search()
|
||||
{ this->do_static_search_ = false; }
|
||||
|
||||
bool do_static_search_;
|
||||
};
|
||||
|
||||
// A single file or library argument from the command line.
|
||||
|
||||
class Input_argument
|
||||
{
|
||||
public:
|
||||
Input_argument(const char* name, const Position_dependent_options& options)
|
||||
: name_(name), options_(options)
|
||||
{ }
|
||||
|
||||
const char*
|
||||
name() const
|
||||
{ return this->name_; }
|
||||
|
||||
const Position_dependent_options&
|
||||
options() const
|
||||
{ return this->options_; }
|
||||
|
||||
bool
|
||||
is_lib() const
|
||||
{ return this->name_[0] == '-' && this->name_[1] == 'l'; }
|
||||
|
||||
const char*
|
||||
lib_basename() const
|
||||
{ return this->name_ + 2; }
|
||||
|
||||
private:
|
||||
const char* name_;
|
||||
Position_dependent_options options_;
|
||||
};
|
||||
|
||||
// All the information read from the command line.
|
||||
|
||||
class Command_line
|
||||
{
|
||||
public:
|
||||
Command_line();
|
||||
|
||||
// Process the command line options. This will exit with an
|
||||
// appropriate error message if an unrecognized option is seen.
|
||||
void
|
||||
process(int argc, char** argv);
|
||||
|
||||
const General_options&
|
||||
options() const
|
||||
{ return this->options_; }
|
||||
|
||||
typedef std::list<Input_argument> Input_argument_list;
|
||||
|
||||
const Input_argument_list&
|
||||
inputs() const
|
||||
{ return this->inputs_; }
|
||||
|
||||
private:
|
||||
void usage() ATTRIBUTE_NORETURN;
|
||||
void usage(const char* msg, const char* opt) ATTRIBUTE_NORETURN;
|
||||
void usage(const char* msg, char opt) ATTRIBUTE_NORETURN;
|
||||
void apply_option(const gold::options::One_option&, const char*);
|
||||
|
||||
General_options options_;
|
||||
Position_dependent_options position_options_;
|
||||
Input_argument_list inputs_;
|
||||
};
|
||||
|
||||
} // End namespace gold.
|
||||
|
||||
#endif // !defined(GOLD_OPTIONS_H)
|
|
@ -0,0 +1,256 @@
|
|||
# Makefile for program source directory in GNU NLS utilities package.
|
||||
# Copyright (C) 1995, 1996, 1997 by Ulrich Drepper <drepper@gnu.ai.mit.edu>
|
||||
# Copyright 2003, 2006 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file may be copied and used freely without restrictions. It can
|
||||
# be used in projects which are not available under the GNU Public License
|
||||
# but which still want to provide support for the GNU gettext functionality.
|
||||
# Please note that the actual code is *not* freely available.
|
||||
|
||||
PACKAGE = @PACKAGE@
|
||||
VERSION = @VERSION@
|
||||
|
||||
SHELL = /bin/sh
|
||||
@SET_MAKE@
|
||||
|
||||
srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
VPATH = @srcdir@
|
||||
top_builddir = @top_builddir@
|
||||
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
datadir = $(prefix)/@DATADIRNAME@
|
||||
localedir = $(datadir)/locale
|
||||
gnulocaledir = $(prefix)/share/locale
|
||||
gettextsrcdir = $(prefix)/share/gettext/po
|
||||
subdir = po
|
||||
|
||||
DESTDIR =
|
||||
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
MKINSTALLDIRS = @MKINSTALLDIRS@
|
||||
|
||||
CC = @CC@
|
||||
GENCAT = @GENCAT@
|
||||
GMSGFMT = PATH=../src:$$PATH @GMSGFMT@
|
||||
MSGFMT = @MSGFMT@
|
||||
XGETTEXT = PATH=../src:$$PATH @XGETTEXT@
|
||||
MSGMERGE = PATH=../src:$$PATH msgmerge
|
||||
|
||||
DEFS = @DEFS@
|
||||
CFLAGS = @CFLAGS@
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
|
||||
INCLUDES = -I.. -I$(top_srcdir)/intl
|
||||
|
||||
COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) $(XCFLAGS)
|
||||
|
||||
SOURCES = cat-id-tbl.c
|
||||
POFILES = @POFILES@
|
||||
GMOFILES = @GMOFILES@
|
||||
DISTFILES = ChangeLog Makefile.in.in POTFILES.in $(PACKAGE).pot \
|
||||
stamp-cat-id $(POFILES) $(GMOFILES) $(SOURCES)
|
||||
|
||||
POTFILES = \
|
||||
|
||||
CATALOGS = @CATALOGS@
|
||||
CATOBJEXT = @CATOBJEXT@
|
||||
INSTOBJEXT = @INSTOBJEXT@
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .c .o .po .pox .gmo .mo .msg .cat
|
||||
|
||||
.c.o:
|
||||
$(COMPILE) $<
|
||||
|
||||
.po.pox:
|
||||
$(MAKE) $(PACKAGE).pot
|
||||
$(MSGMERGE) $< $(srcdir)/$(PACKAGE).pot -o $*.pox
|
||||
|
||||
.po.mo:
|
||||
$(MSGFMT) -o $@ $<
|
||||
|
||||
.po.gmo:
|
||||
file=$(srcdir)/`echo $* | sed 's,.*/,,'`.gmo \
|
||||
&& rm -f $$file && $(GMSGFMT) -o $$file $<
|
||||
|
||||
.po.cat:
|
||||
sed -f ../intl/po2msg.sed < $< > $*.msg \
|
||||
&& rm -f $@ && $(GENCAT) $@ $*.msg
|
||||
|
||||
|
||||
all: all-@USE_NLS@
|
||||
|
||||
all-yes: $(CATALOGS) @MAINT@ $(PACKAGE).pot
|
||||
all-no:
|
||||
|
||||
$(srcdir)/$(PACKAGE).pot: $(POTFILES)
|
||||
$(XGETTEXT) --default-domain=$(PACKAGE) --directory=$(top_srcdir) \
|
||||
--add-comments --keyword=_ --keyword=N_ \
|
||||
--files-from=$(srcdir)/POTFILES.in
|
||||
rm -f $(srcdir)/$(PACKAGE).pot
|
||||
mv $(PACKAGE).po $(srcdir)/$(PACKAGE).pot
|
||||
|
||||
$(srcdir)/cat-id-tbl.c: stamp-cat-id; @:
|
||||
$(srcdir)/stamp-cat-id: $(PACKAGE).pot
|
||||
rm -f cat-id-tbl.tmp
|
||||
sed -f ../intl/po2tbl.sed $(srcdir)/$(PACKAGE).pot \
|
||||
| sed -e "s/@PACKAGE NAME@/$(PACKAGE)/" > cat-id-tbl.tmp
|
||||
if cmp -s cat-id-tbl.tmp $(srcdir)/cat-id-tbl.c; then \
|
||||
rm cat-id-tbl.tmp; \
|
||||
else \
|
||||
echo cat-id-tbl.c changed; \
|
||||
rm -f $(srcdir)/cat-id-tbl.c; \
|
||||
mv cat-id-tbl.tmp $(srcdir)/cat-id-tbl.c; \
|
||||
fi
|
||||
cd $(srcdir) && rm -f stamp-cat-id && echo timestamp > stamp-cat-id
|
||||
|
||||
|
||||
install: install-exec install-data
|
||||
install-exec:
|
||||
install-info:
|
||||
install-html:
|
||||
install-data: install-data-@USE_NLS@
|
||||
install-data-no: all
|
||||
install-data-yes: all
|
||||
if test -r $(MKINSTALLDIRS); then \
|
||||
$(MKINSTALLDIRS) $(DESTDIR)$(datadir); \
|
||||
else \
|
||||
$(top_srcdir)/mkinstalldirs $(DESTDIR)$(datadir); \
|
||||
fi
|
||||
@catalogs='$(CATALOGS)'; \
|
||||
for cat in $$catalogs; do \
|
||||
cat=`basename $$cat`; \
|
||||
case "$$cat" in \
|
||||
*.gmo) destdir=$(gnulocaledir);; \
|
||||
*) destdir=$(localedir);; \
|
||||
esac; \
|
||||
lang=`echo $$cat | sed 's/\$(CATOBJEXT)$$//'`; \
|
||||
dir=$(DESTDIR)$$destdir/$$lang/LC_MESSAGES; \
|
||||
if test -r $(MKINSTALLDIRS); then \
|
||||
$(MKINSTALLDIRS) $$dir; \
|
||||
else \
|
||||
$(top_srcdir)/mkinstalldirs $$dir; \
|
||||
fi; \
|
||||
if test -r $$cat; then \
|
||||
$(INSTALL_DATA) $$cat $$dir/$(PACKAGE)$(INSTOBJEXT); \
|
||||
echo "installing $$cat as $$dir/$(PACKAGE)$(INSTOBJEXT)"; \
|
||||
else \
|
||||
$(INSTALL_DATA) $(srcdir)/$$cat $$dir/$(PACKAGE)$(INSTOBJEXT); \
|
||||
echo "installing $(srcdir)/$$cat as" \
|
||||
"$$dir/$(PACKAGE)$(INSTOBJEXT)"; \
|
||||
fi; \
|
||||
if test -r $$cat.m; then \
|
||||
$(INSTALL_DATA) $$cat.m $$dir/$(PACKAGE)$(INSTOBJEXT).m; \
|
||||
echo "installing $$cat.m as $$dir/$(PACKAGE)$(INSTOBJEXT).m"; \
|
||||
else \
|
||||
if test -r $(srcdir)/$$cat.m ; then \
|
||||
$(INSTALL_DATA) $(srcdir)/$$cat.m \
|
||||
$$dir/$(PACKAGE)$(INSTOBJEXT).m; \
|
||||
echo "installing $(srcdir)/$$cat as" \
|
||||
"$$dir/$(PACKAGE)$(INSTOBJEXT).m"; \
|
||||
else \
|
||||
true; \
|
||||
fi; \
|
||||
fi; \
|
||||
done
|
||||
if test "$(PACKAGE)" = "gettext"; then \
|
||||
if test -r $(MKINSTALLDIRS); then \
|
||||
$(MKINSTALLDIRS) $(DESTDIR)$(gettextsrcdir); \
|
||||
else \
|
||||
$(top_srcdir)/mkinstalldirs $(DESTDIR)$(gettextsrcdir); \
|
||||
fi; \
|
||||
$(INSTALL_DATA) $(srcdir)/Makefile.in.in \
|
||||
$(DESTDIR)$(gettextsrcdir)/Makefile.in.in; \
|
||||
else \
|
||||
: ; \
|
||||
fi
|
||||
|
||||
# Define this as empty until I found a useful application.
|
||||
installcheck:
|
||||
|
||||
uninstall:
|
||||
catalogs='$(CATALOGS)'; \
|
||||
for cat in $$catalogs; do \
|
||||
cat=`basename $$cat`; \
|
||||
lang=`echo $$cat | sed 's/\$(CATOBJEXT)$$//'`; \
|
||||
rm -f $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(PACKAGE)$(INSTOBJEXT); \
|
||||
rm -f $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(PACKAGE)$(INSTOBJEXT).m; \
|
||||
rm -f $(DESTDIR)$(gnulocaledir)/$$lang/LC_MESSAGES/$(PACKAGE)$(INSTOBJEXT); \
|
||||
rm -f $(DESTDIR)$(gnulocaledir)/$$lang/LC_MESSAGES/$(PACKAGE)$(INSTOBJEXT).m; \
|
||||
done
|
||||
rm -f $(DESTDIR)$(gettextsrcdir)/po-Makefile.in.in
|
||||
|
||||
check: all
|
||||
|
||||
cat-id-tbl.o: ../intl/libgettext.h
|
||||
|
||||
html dvi pdf ps info tags TAGS ID:
|
||||
|
||||
mostlyclean:
|
||||
rm -f core core.* *.pox $(PACKAGE).po *.old.po cat-id-tbl.tmp
|
||||
rm -fr *.o
|
||||
|
||||
clean: mostlyclean
|
||||
|
||||
distclean: clean
|
||||
rm -f Makefile Makefile.in POTFILES *.mo *.msg *.cat *.cat.m
|
||||
|
||||
maintainer-clean: distclean
|
||||
@echo "This command is intended for maintainers to use;"
|
||||
@echo "it deletes files that may require special tools to rebuild."
|
||||
rm -f $(GMOFILES)
|
||||
|
||||
distdir = ../$(PACKAGE)-$(VERSION)/$(subdir)
|
||||
dist distdir: update-po $(DISTFILES)
|
||||
dists="$(DISTFILES)"; \
|
||||
for file in $$dists; do \
|
||||
ln $(srcdir)/$$file $(distdir) 2> /dev/null \
|
||||
|| cp -p $(srcdir)/$$file $(distdir); \
|
||||
done
|
||||
|
||||
update-po: Makefile
|
||||
$(MAKE) $(PACKAGE).pot
|
||||
PATH=`pwd`/../src:$$PATH; \
|
||||
cd $(srcdir); \
|
||||
catalogs='$(CATALOGS)'; \
|
||||
for cat in $$catalogs; do \
|
||||
cat=`basename $$cat`; \
|
||||
lang=`echo $$cat | sed 's/\$(CATOBJEXT)$$//'`; \
|
||||
mv $$lang.po $$lang.old.po; \
|
||||
echo "$$lang:"; \
|
||||
if $(MSGMERGE) $$lang.old.po $(PACKAGE).pot -o $$lang.po; then \
|
||||
rm -f $$lang.old.po; \
|
||||
else \
|
||||
echo "msgmerge for $$cat failed!"; \
|
||||
rm -f $$lang.po; \
|
||||
mv $$lang.old.po $$lang.po; \
|
||||
fi; \
|
||||
done
|
||||
|
||||
POTFILES: POTFILES.in
|
||||
( if test 'x$(srcdir)' != 'x.'; then \
|
||||
posrcprefix='$(top_srcdir)/'; \
|
||||
else \
|
||||
posrcprefix="../"; \
|
||||
fi; \
|
||||
rm -f $@-t $@ \
|
||||
&& (sed -e '/^#/d' -e '/^[ ]*$$/d' \
|
||||
-e "s@.*@ $$posrcprefix& \\\\@" < $(srcdir)/$@.in \
|
||||
| sed -e '$$s/\\$$//') > $@-t \
|
||||
&& chmod a-w $@-t \
|
||||
&& mv $@-t $@ )
|
||||
|
||||
POTFILES.in: @MAINT@ ../Makefile
|
||||
cd .. && $(MAKE) po/POTFILES.in
|
||||
|
||||
Makefile: Make-in ../config.status POTFILES
|
||||
cd .. \
|
||||
&& CONFIG_FILES=$(subdir)/Makefile.in:$(subdir)/Make-in \
|
||||
CONFIG_HEADERS= $(SHELL) ./config.status
|
||||
|
||||
# Tell versions [3.59,3.63) of GNU make not to export all variables.
|
||||
# Otherwise a system limit (for SysV at least) may be exceeded.
|
||||
.NOEXPORT:
|
|
@ -0,0 +1,19 @@
|
|||
dirsearch.cc
|
||||
dirsearch.h
|
||||
fileread.cc
|
||||
fileread.h
|
||||
gold.cc
|
||||
gold.h
|
||||
gold-threads.cc
|
||||
gold-threads.h
|
||||
object.cc
|
||||
object.h
|
||||
options.cc
|
||||
options.h
|
||||
readsyms.cc
|
||||
readsyms.h
|
||||
symtab.h
|
||||
target.h
|
||||
targetsize.h
|
||||
workqueue.cc
|
||||
workqueue.h
|
|
@ -0,0 +1,216 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2006-08-04 14:23-0700\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=CHARSET\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: dirsearch.cc:50
|
||||
#, c-format
|
||||
msgid "can not read directory %s"
|
||||
msgstr ""
|
||||
|
||||
#: fileread.cc:56
|
||||
#, c-format
|
||||
msgid "%s: warning: close(%s) failed: %s"
|
||||
msgstr ""
|
||||
|
||||
#: fileread.cc:131
|
||||
#, c-format
|
||||
msgid "%s: %s: lseek to %lld failed: %s"
|
||||
msgstr ""
|
||||
|
||||
#: fileread.cc:141
|
||||
#, c-format
|
||||
msgid "%s: %s: read failed: %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: fileread.cc:151
|
||||
#, c-format
|
||||
msgid "%s: %s: file too short: read only %lld of %lld bytes at %lld\n"
|
||||
msgstr ""
|
||||
|
||||
#: fileread.cc:267
|
||||
#, c-format
|
||||
msgid "%s: cannot find %s"
|
||||
msgstr ""
|
||||
|
||||
#: fileread.cc:275
|
||||
#, c-format
|
||||
msgid "%s: cannot open %s: %s"
|
||||
msgstr ""
|
||||
|
||||
#: gold.cc:71
|
||||
msgid "no input files"
|
||||
msgstr ""
|
||||
|
||||
#: gold-threads.cc:48
|
||||
msgid "pthead_mutextattr_init failed"
|
||||
msgstr ""
|
||||
|
||||
#: gold-threads.cc:51
|
||||
msgid "pthread_mutextattr_settype failed"
|
||||
msgstr ""
|
||||
|
||||
#: gold-threads.cc:55
|
||||
msgid "pthread_mutex_init failed"
|
||||
msgstr ""
|
||||
|
||||
#: gold-threads.cc:58
|
||||
msgid "pthread_mutexattr_destroy failed"
|
||||
msgstr ""
|
||||
|
||||
#: gold-threads.cc:64
|
||||
msgid "pthread_mutex_destroy failed"
|
||||
msgstr ""
|
||||
|
||||
#: gold-threads.cc:71
|
||||
msgid "pthread_mutex_lock failed"
|
||||
msgstr ""
|
||||
|
||||
#: gold-threads.cc:78
|
||||
msgid "pthread_mutex_unlock failed"
|
||||
msgstr ""
|
||||
|
||||
#: gold-threads.cc:159
|
||||
msgid "pthread_cond_init failed"
|
||||
msgstr ""
|
||||
|
||||
#: gold-threads.cc:165
|
||||
msgid "pthread_cond_destroy failed"
|
||||
msgstr ""
|
||||
|
||||
#: gold-threads.cc:172
|
||||
msgid "pthread_cond_wait failed"
|
||||
msgstr ""
|
||||
|
||||
#: gold-threads.cc:179
|
||||
msgid "pthread_cond_signal failed"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:56
|
||||
#, c-format
|
||||
msgid "%s: %s: bad e_ehsize field (%d != %d)\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:63
|
||||
#, c-format
|
||||
msgid "%s: %s: bad e_shentsize field (%d != %d)\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:154
|
||||
#, c-format
|
||||
msgid "%s: %s: invalid symbol table name index: %u\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:164
|
||||
#, c-format
|
||||
msgid "%s: %s: symbol table name section has wrong type: %u\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:206
|
||||
#, c-format
|
||||
msgid "%s: %s: invalid symbol name offset %u for symbol %d\n"
|
||||
msgstr ""
|
||||
|
||||
#. elfcpp::ET_DYN
|
||||
#: object.cc:249
|
||||
#, c-format
|
||||
msgid "%s: %s: dynamic objects are not yet supported\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:273 object.cc:326 object.cc:347
|
||||
#, c-format
|
||||
msgid "%s: %s: ELF file too short\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:282
|
||||
#, c-format
|
||||
msgid "%s: %s: invalid ELF version 0\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:285
|
||||
#, c-format
|
||||
msgid "%s: %s: unsupported ELF version %d\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:293
|
||||
#, c-format
|
||||
msgid "%s: %s: invalid ELF class 0\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:300
|
||||
#, c-format
|
||||
msgid "%s: %s: unsupported ELF class %d\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:308
|
||||
#, c-format
|
||||
msgid "%s: %s: invalid ELF data encoding\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:315
|
||||
#, c-format
|
||||
msgid "%s: %s: unsupported ELF data encoding %d\n"
|
||||
msgstr ""
|
||||
|
||||
#: options.cc:84
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Usage: %s [options] file...\n"
|
||||
"Options:\n"
|
||||
msgstr ""
|
||||
|
||||
#: options.cc:193
|
||||
msgid "Add directory to search path"
|
||||
msgstr ""
|
||||
|
||||
#: options.cc:194
|
||||
msgid "-L DIR, --library-path DIR"
|
||||
msgstr ""
|
||||
|
||||
#: options.cc:196
|
||||
msgid "Generate relocatable output"
|
||||
msgstr ""
|
||||
|
||||
#: options.cc:198
|
||||
msgid "Do not link against shared libraries"
|
||||
msgstr ""
|
||||
|
||||
#: options.cc:200
|
||||
msgid "Report usage information"
|
||||
msgstr ""
|
||||
|
||||
#: options.cc:294 options.cc:345
|
||||
msgid "missing argument"
|
||||
msgstr ""
|
||||
|
||||
#: options.cc:307 options.cc:354
|
||||
msgid "unknown option"
|
||||
msgstr ""
|
||||
|
||||
#: options.cc:393
|
||||
#, c-format
|
||||
msgid "%s: use the --help option for usage information\n"
|
||||
msgstr ""
|
||||
|
||||
#: options.cc:402
|
||||
#, c-format
|
||||
msgid "%s: %s: %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: options.cc:411
|
||||
#, c-format
|
||||
msgid "%s: -%c: %s\n"
|
||||
msgstr ""
|
|
@ -0,0 +1,123 @@
|
|||
// readsyms.cc -- read input file symbols for gold
|
||||
|
||||
#include "gold.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "elfcpp.h"
|
||||
#include "options.h"
|
||||
#include "dirsearch.h"
|
||||
#include "readsyms.h"
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
||||
// Class read_symbols.
|
||||
|
||||
Read_symbols::~Read_symbols()
|
||||
{
|
||||
// The this_blocker_ and next_blocker_ pointers are passed on to the
|
||||
// Add_symbols task.
|
||||
}
|
||||
|
||||
// Return whether a Read_symbols task is runnable. We need write
|
||||
// access to the symbol table. We can read an ordinary input file
|
||||
// immediately. For an archive specified using -l, we have to wait
|
||||
// until the search path is complete.
|
||||
|
||||
Task::Is_runnable_type
|
||||
Read_symbols::is_runnable(Workqueue*)
|
||||
{
|
||||
if (this->input_.is_lib() && this->dirpath_.token().is_blocked())
|
||||
return IS_BLOCKED;
|
||||
|
||||
return IS_RUNNABLE;
|
||||
}
|
||||
|
||||
// Return a Task_locker for a Read_symbols task. We don't need any
|
||||
// locks here.
|
||||
|
||||
Task_locker*
|
||||
Read_symbols::locks(Workqueue*)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Run a Read_symbols task. This is where we actually read the
|
||||
// symbols and relocations.
|
||||
|
||||
void
|
||||
Read_symbols::run(Workqueue* workqueue)
|
||||
{
|
||||
// We don't keep track of Input_file objects, so this is a memory
|
||||
// leak.
|
||||
Input_file* input_file = new Input_file(this->input_);
|
||||
input_file->open(this->options_, this->dirpath_);
|
||||
|
||||
// Read enough of the file to pick up the entire ELF header.
|
||||
|
||||
int ehdr_size = elfcpp::Elf_sizes<64>::ehdr_size;
|
||||
off_t bytes;
|
||||
const unsigned char* p = input_file->file().get_view(0, ehdr_size, &bytes);
|
||||
if (bytes >= 4)
|
||||
{
|
||||
static unsigned char elfmagic[4] =
|
||||
{
|
||||
elfcpp::ELFMAG0, elfcpp::ELFMAG1,
|
||||
elfcpp::ELFMAG2, elfcpp::ELFMAG3
|
||||
};
|
||||
if (memcmp(p, elfmagic, 4) == 0)
|
||||
{
|
||||
// This is an ELF object.
|
||||
Object* obj = make_elf_object(this->input_.name(), input_file, 0,
|
||||
p, bytes);
|
||||
|
||||
Read_symbols_data sd = obj->read_symbols();
|
||||
workqueue->queue(new Add_symbols(obj, sd, this->this_blocker_,
|
||||
this->next_blocker_));
|
||||
|
||||
// Opening the file locked it, so now we need to unlock it.
|
||||
input_file->file().unlock();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Here we have to handle archives and any other input file
|
||||
// types we need.
|
||||
gold_fatal("only objects are currently supported", false);
|
||||
}
|
||||
|
||||
// Class Add_symbols.
|
||||
|
||||
Add_symbols::~Add_symbols()
|
||||
{
|
||||
if (this->this_blocker_ != NULL)
|
||||
delete this->this_blocker_;
|
||||
// next_blocker_ is deleted by the task associated with the next
|
||||
// input file.
|
||||
}
|
||||
|
||||
// We are blocked by this_blocker_. We block next_blocker_.
|
||||
|
||||
Task::Is_runnable_type
|
||||
Add_symbols::is_runnable(Workqueue*)
|
||||
{
|
||||
if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked())
|
||||
return IS_BLOCKED;
|
||||
return IS_RUNNABLE;
|
||||
}
|
||||
|
||||
Task_locker*
|
||||
Add_symbols::locks(Workqueue* workqueue)
|
||||
{
|
||||
return new Task_locker_block(*this->next_blocker_, workqueue);
|
||||
}
|
||||
|
||||
void
|
||||
Add_symbols::run(Workqueue*)
|
||||
{
|
||||
this->object_->add_symbols(this->sd_);
|
||||
}
|
||||
|
||||
} // End namespace gold.
|
|
@ -0,0 +1,95 @@
|
|||
// readsyms.h -- read input file symbols for gold -*- C++ -*-
|
||||
|
||||
#ifndef GOLD_READSYMS_H
|
||||
#define GOLD_READSYMS_H
|
||||
|
||||
#include "targetsize.h"
|
||||
#include "workqueue.h"
|
||||
#include "object.h"
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
||||
// This Task is responsible for reading the symbols from an input
|
||||
// file. This also includes reading the relocations so that we can
|
||||
// check for any that require a PLT and/or a GOT. After the data has
|
||||
// been read, this queues up another task to actually add the symbols
|
||||
// to the symbol table. The tasks are separated because the file
|
||||
// reading can occur in parallel but adding the symbols must be done
|
||||
// in the order of the input files.
|
||||
|
||||
class Read_symbols : public Task
|
||||
{
|
||||
public:
|
||||
// DIRPATH is the list of directories to search for libraries.
|
||||
// INPUT is the file to read. THIS_BLOCKER is used to prevent the
|
||||
// associated Add_symbols task from running before the previous one
|
||||
// has completed; it will be NULL for the first task. NEXT_BLOCKER
|
||||
// is used to block the next input file from adding symbols.
|
||||
Read_symbols(const General_options& options, const Dirsearch& dirpath,
|
||||
const Input_argument& input, Task_token* this_blocker,
|
||||
Task_token* next_blocker)
|
||||
: options_(options), dirpath_(dirpath), input_(input),
|
||||
this_blocker_(this_blocker), next_blocker_(next_blocker)
|
||||
{ }
|
||||
|
||||
~Read_symbols();
|
||||
|
||||
// The standard Task methods.
|
||||
|
||||
Is_runnable_type
|
||||
is_runnable(Workqueue*);
|
||||
|
||||
Task_locker*
|
||||
locks(Workqueue*);
|
||||
|
||||
void
|
||||
run(Workqueue*);
|
||||
|
||||
private:
|
||||
const General_options& options_;
|
||||
const Dirsearch& dirpath_;
|
||||
const Input_argument& input_;
|
||||
Task_token* this_blocker_;
|
||||
Task_token* next_blocker_;
|
||||
};
|
||||
|
||||
// This Task handles adding the symbols to the symbol table. These
|
||||
// tasks must be run in the same order as the arguments appear on the
|
||||
// command line.
|
||||
|
||||
class Add_symbols : public Task
|
||||
{
|
||||
public:
|
||||
// THIS_BLOCKER is used to prevent this task from running before the
|
||||
// one for the previous input file. NEXT_BLOCKER is used to prevent
|
||||
// the next task from running.
|
||||
Add_symbols(Object* object, Read_symbols_data sd, Task_token* this_blocker,
|
||||
Task_token* next_blocker)
|
||||
: object_(object), sd_(sd), this_blocker_(this_blocker),
|
||||
next_blocker_(next_blocker)
|
||||
{ }
|
||||
|
||||
~Add_symbols();
|
||||
|
||||
// The standard Task methods.
|
||||
|
||||
Is_runnable_type
|
||||
is_runnable(Workqueue*);
|
||||
|
||||
Task_locker*
|
||||
locks(Workqueue*);
|
||||
|
||||
void
|
||||
run(Workqueue*);
|
||||
|
||||
private:
|
||||
Object* object_;
|
||||
Read_symbols_data sd_;
|
||||
Task_token* this_blocker_;
|
||||
Task_token* next_blocker_;
|
||||
};
|
||||
|
||||
} // end namespace gold
|
||||
|
||||
#endif // !defined(GOLD_READSYMS_H)
|
|
@ -0,0 +1,80 @@
|
|||
// symtab.h -- the gold symbol table -*- C++ -*-
|
||||
|
||||
// Symbol_table
|
||||
// The symbol table.
|
||||
|
||||
#include "gold.h"
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "elfcpp.h"
|
||||
#include "targetsize.h"
|
||||
#include "object.h"
|
||||
#include "workqueue.h"
|
||||
|
||||
#ifndef GOLD_SYMTAB_H
|
||||
#define GOLD_SYMTAB_H
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
||||
// An entry in the symbol table. The symbol table can have a lot of
|
||||
// entries, so we don't want this class to get too big.
|
||||
|
||||
template<int size>
|
||||
class Symbol
|
||||
{
|
||||
public:
|
||||
typedef typename elfcpp::Elf_types<size>::Elf_Addr Value;
|
||||
typedef typename Size_types<size>::Unsigned_type Size;
|
||||
|
||||
private:
|
||||
// Every symbol has a unique name, more or less, so we use
|
||||
// std::string for the name. There are only a few versions in a
|
||||
// given link, so for them we point into a pool.
|
||||
std::string name_;
|
||||
const char* version_;
|
||||
Object* object_;
|
||||
unsigned int shnum_;
|
||||
Value value_;
|
||||
Size size_;
|
||||
elfcpp::STT type_ : 4;
|
||||
elfcpp::STB binding_ : 4;
|
||||
elfcpp:STV visibility_ : 2;
|
||||
unsigned int other_ : 6;
|
||||
};
|
||||
|
||||
// The main linker symbol table.
|
||||
|
||||
template<int size>
|
||||
class Symbol_table
|
||||
{
|
||||
public:
|
||||
Symbol_table();
|
||||
|
||||
// Return a pointer to a symbol specified by name.
|
||||
Symbol*
|
||||
lookup(const std::string& name) const;
|
||||
|
||||
// Return a pointer to a symbol specified by name plus version.
|
||||
Symbol*
|
||||
lookup(const std::string& name, const char* version) const;
|
||||
|
||||
Task_token&
|
||||
token() const
|
||||
{ return this->token_; }
|
||||
|
||||
private:
|
||||
Symbol_table(const Symbol_table&);
|
||||
Symbol_table& operator=(const Symbol_table&);
|
||||
|
||||
typedef std::pair<std::string, std::string> Symbol_table_key;
|
||||
|
||||
Unordered_map<Symbol_table_key, Symbol<size>*> table_;
|
||||
Task_token token_;
|
||||
};
|
||||
|
||||
} // End namespace gold.
|
||||
|
||||
#endif // !defined(GOLD_SYMTAB_H)
|
|
@ -0,0 +1,29 @@
|
|||
// target.h -- target support for gold
|
||||
|
||||
// The abstract class Target is the interface for target specific
|
||||
// support. It defines abstract methods which each target must
|
||||
// implement. Typically there will be one target per processor, but
|
||||
// in some cases it may be necessary to have subclasses.
|
||||
|
||||
// For speed and consistency we want to use inline functions to handle
|
||||
// relocation processing. So besides implementations of the abstract
|
||||
// methods, each target is expected to define a template
|
||||
// specialization of the relocation functions.
|
||||
|
||||
#ifndef GOLD_TARGET_H
|
||||
#define GOLD_TARGET_H
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
||||
class Target
|
||||
{
|
||||
public:
|
||||
};
|
||||
|
||||
extern Target* select_target(int machine, int size, bool big_endian,
|
||||
int osabi, int abiversion);
|
||||
|
||||
} // End namespace gold.
|
||||
|
||||
#endif // !defined(GOLD_TARGET_H)
|
|
@ -0,0 +1,56 @@
|
|||
// targetsize.h -- representations which change size based on the target
|
||||
|
||||
#ifndef GOLD_TARGETSIZE_H
|
||||
#define GOLD_TARGETSIZE_H
|
||||
|
||||
// Tell GNU/Linux inttypes.h that we want the formatting macros.
|
||||
#define __STDC_FORMAT_MACROS
|
||||
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
||||
// A template we use to get the right type sizes via specialization.
|
||||
// We never actually use the default version.
|
||||
|
||||
template<int size>
|
||||
struct Size_types
|
||||
{
|
||||
typedef signed char Signed_type;
|
||||
typedef unsigned char Unsigned_type;
|
||||
static const char* signed_printf_dec_format();
|
||||
static const char* unsigned_printf_dec_format();
|
||||
static const char* unsigned_printf_hex_format();
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Size_types<32>
|
||||
{
|
||||
typedef int32_t Signed_type;
|
||||
typedef uint32_t Unsigned_type;
|
||||
static const char* signed_printf_dec_format()
|
||||
{ return PRId32; }
|
||||
static const char* unsigned_printf_dec_format()
|
||||
{ return PRIu32; }
|
||||
static const char* unsigned_printf_hex_format()
|
||||
{ return PRIx32; }
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Size_types<64>
|
||||
{
|
||||
typedef int64_t Signed_type;
|
||||
typedef uint64_t Unsigned_type;
|
||||
static const char* signed_printf_dec_format()
|
||||
{ return PRId64; }
|
||||
static const char* unsigned_printf_dec_format()
|
||||
{ return PRIu64; }
|
||||
static const char* unsigned_printf_hex_format()
|
||||
{ return PRIx64; }
|
||||
};
|
||||
|
||||
} // End namespace gold.
|
||||
|
||||
#endif // !defined(GOLD_TARGETSIZE_H)
|
|
@ -0,0 +1,391 @@
|
|||
// workqueue.cc -- the workqueue for gold
|
||||
|
||||
#include "gold.h"
|
||||
#include "workqueue.h"
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
||||
// Task_token methods.
|
||||
|
||||
Task_token::Task_token()
|
||||
: is_blocker_(false), readers_(0), writer_(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
Task_token::~Task_token()
|
||||
{
|
||||
assert(this->readers_ == 0 && this->writer_ == NULL);
|
||||
}
|
||||
|
||||
bool
|
||||
Task_token::is_readable() const
|
||||
{
|
||||
assert(!this->is_blocker_);
|
||||
return this->writer_ == NULL;
|
||||
}
|
||||
|
||||
void
|
||||
Task_token::add_reader()
|
||||
{
|
||||
assert(!this->is_blocker_);
|
||||
assert(this->is_readable());
|
||||
++this->readers_;
|
||||
}
|
||||
|
||||
void
|
||||
Task_token::remove_reader()
|
||||
{
|
||||
assert(!this->is_blocker_);
|
||||
assert(this->readers_ > 0);
|
||||
--this->readers_;
|
||||
}
|
||||
|
||||
bool
|
||||
Task_token::is_writable() const
|
||||
{
|
||||
assert(!this->is_blocker_);
|
||||
return this->writer_ == NULL && this->readers_ == 0;
|
||||
}
|
||||
|
||||
void
|
||||
Task_token::add_writer(const Task* t)
|
||||
{
|
||||
assert(!this->is_blocker_);
|
||||
assert(this->is_writable());
|
||||
this->writer_ = t;
|
||||
}
|
||||
|
||||
void
|
||||
Task_token::remove_writer(const Task* t)
|
||||
{
|
||||
assert(!this->is_blocker_);
|
||||
assert(this->writer_ == t);
|
||||
this->writer_ = NULL;
|
||||
}
|
||||
|
||||
bool
|
||||
Task_token::has_write_lock(const Task* t)
|
||||
{
|
||||
assert(!this->is_blocker_);
|
||||
return this->writer_ == t;
|
||||
}
|
||||
|
||||
// For blockers, we just use the readers_ field.
|
||||
|
||||
void
|
||||
Task_token::add_blocker()
|
||||
{
|
||||
if (this->readers_ == 0 && this->writer_ == NULL)
|
||||
this->is_blocker_ = true;
|
||||
else
|
||||
assert(this->is_blocker_);
|
||||
++this->readers_;
|
||||
}
|
||||
|
||||
bool
|
||||
Task_token::remove_blocker()
|
||||
{
|
||||
assert(this->is_blocker_ && this->readers_ > 0);
|
||||
--this->readers_;
|
||||
return this->readers_ == 0;
|
||||
}
|
||||
|
||||
bool
|
||||
Task_token::is_blocked() const
|
||||
{
|
||||
assert(this->is_blocker_ || (this->readers_ == 0 && this->writer_ == NULL));
|
||||
return this->readers_ > 0;
|
||||
}
|
||||
|
||||
// The Task_block_token class.
|
||||
|
||||
Task_block_token::Task_block_token(Task_token& token, Workqueue* workqueue)
|
||||
: token_(token), workqueue_(workqueue)
|
||||
{
|
||||
// We must increment the block count when the task is created and
|
||||
// put on the queue. This object is created when the task is run,
|
||||
// so we don't increment the block count here.
|
||||
assert(this->token_.is_blocked());
|
||||
}
|
||||
|
||||
Task_block_token::~Task_block_token()
|
||||
{
|
||||
if (this->token_.remove_blocker())
|
||||
{
|
||||
// Tell the workqueue that a blocker was cleared. This is
|
||||
// always called in the main thread, so no locking is required.
|
||||
this->workqueue_->cleared_blocker();
|
||||
}
|
||||
}
|
||||
|
||||
// The Workqueue_runner abstract class.
|
||||
|
||||
class Workqueue_runner
|
||||
{
|
||||
public:
|
||||
Workqueue_runner(Workqueue* workqueue)
|
||||
: workqueue_(workqueue)
|
||||
{ }
|
||||
virtual ~Workqueue_runner()
|
||||
{ }
|
||||
|
||||
// Run a task. This is always called in the main thread.
|
||||
virtual void run(Task*, Task_locker*) = 0;
|
||||
|
||||
protected:
|
||||
// This is called by an implementation when a task is completed.
|
||||
void completed(Task* t, Task_locker* tl)
|
||||
{ this->workqueue_->completed(t, tl); }
|
||||
|
||||
Workqueue* get_workqueue() const
|
||||
{ return this->workqueue_; }
|
||||
|
||||
private:
|
||||
Workqueue* workqueue_;
|
||||
};
|
||||
|
||||
// The simple single-threaded implementation of Workqueue_runner.
|
||||
|
||||
class Workqueue_runner_single : public Workqueue_runner
|
||||
{
|
||||
public:
|
||||
Workqueue_runner_single(Workqueue* workqueue)
|
||||
: Workqueue_runner(workqueue)
|
||||
{ }
|
||||
~Workqueue_runner_single()
|
||||
{ }
|
||||
|
||||
void run(Task*, Task_locker*);
|
||||
};
|
||||
|
||||
void
|
||||
Workqueue_runner_single::run(Task* t, Task_locker* tl)
|
||||
{
|
||||
t->run(this->get_workqueue());
|
||||
this->completed(t, tl);
|
||||
}
|
||||
|
||||
// Workqueue methods.
|
||||
|
||||
Workqueue::Workqueue(const General_options&)
|
||||
: tasks_lock_(),
|
||||
tasks_(),
|
||||
completed_lock_(),
|
||||
completed_(),
|
||||
running_(0),
|
||||
completed_condvar_(this->completed_lock_),
|
||||
cleared_blockers_(0)
|
||||
{
|
||||
// At some point we will select the specific implementation of
|
||||
// Workqueue_runner to use based on the command line options.
|
||||
this->runner_ = new Workqueue_runner_single(this);
|
||||
}
|
||||
|
||||
Workqueue::~Workqueue()
|
||||
{
|
||||
assert(this->tasks_.empty());
|
||||
assert(this->completed_.empty());
|
||||
assert(this->running_ == 0);
|
||||
}
|
||||
|
||||
void
|
||||
Workqueue::queue(Task* t)
|
||||
{
|
||||
Hold_lock hl(this->tasks_lock_);
|
||||
this->tasks_.push_back(t);
|
||||
}
|
||||
|
||||
// Clear the list of completed tasks. Return whether we cleared
|
||||
// anything. The completed_lock_ must be held when this is called.
|
||||
|
||||
bool
|
||||
Workqueue::clear_completed()
|
||||
{
|
||||
if (this->completed_.empty())
|
||||
return false;
|
||||
do
|
||||
{
|
||||
delete this->completed_.front();
|
||||
this->completed_.pop_front();
|
||||
}
|
||||
while (!this->completed_.empty());
|
||||
return true;
|
||||
}
|
||||
|
||||
// Find a runnable task in TASKS, which is non-empty. Return NULL if
|
||||
// none could be found. The tasks_lock_ must be held when this is
|
||||
// called. Sets ALL_BLOCKED if all non-runnable tasks are waiting on
|
||||
// a blocker.
|
||||
|
||||
Task*
|
||||
Workqueue::find_runnable(Task_list& tasks, bool* all_blocked)
|
||||
{
|
||||
Task* tlast = tasks.back();
|
||||
*all_blocked = true;
|
||||
while (true)
|
||||
{
|
||||
Task* t = tasks.front();
|
||||
tasks.pop_front();
|
||||
|
||||
Task::Is_runnable_type is_runnable = t->is_runnable(this);
|
||||
if (is_runnable == Task::IS_RUNNABLE)
|
||||
return t;
|
||||
|
||||
if (is_runnable != Task::IS_BLOCKED)
|
||||
*all_blocked = false;
|
||||
|
||||
tasks.push_back(t);
|
||||
|
||||
if (t == tlast)
|
||||
{
|
||||
// We couldn't find any runnable task. If there are any
|
||||
// completed tasks, free their locks and try again.
|
||||
|
||||
{
|
||||
Hold_lock hl2(this->completed_lock_);
|
||||
|
||||
if (!this->clear_completed())
|
||||
{
|
||||
// There had better be some tasks running, or we will
|
||||
// never find a runnable task.
|
||||
assert(this->running_ > 0);
|
||||
|
||||
// We couldn't find any runnable tasks, and we
|
||||
// couldn't release any locks.
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// We're going around again, so recompute ALL_BLOCKED.
|
||||
*all_blocked = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Process all the tasks on the workqueue. This is the main loop in
|
||||
// the linker. Note that as we process tasks, new tasks will be
|
||||
// added.
|
||||
|
||||
void
|
||||
Workqueue::process()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
Task* t;
|
||||
bool empty;
|
||||
bool all_blocked;
|
||||
|
||||
{
|
||||
Hold_lock hl(this->tasks_lock_);
|
||||
|
||||
if (this->tasks_.empty())
|
||||
{
|
||||
t = NULL;
|
||||
empty = true;
|
||||
all_blocked = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
t = this->find_runnable(this->tasks_, &all_blocked);
|
||||
empty = false;
|
||||
}
|
||||
}
|
||||
|
||||
// If T != NULL, it is a task we can run.
|
||||
// If T == NULL && empty, then there are no tasks waiting to
|
||||
// be run at this level.
|
||||
// If T == NULL && !empty, then there tasks waiting to be
|
||||
// run at this level, but they are waiting for something to
|
||||
// unlock.
|
||||
|
||||
if (t != NULL)
|
||||
this->run(t);
|
||||
else if (!empty)
|
||||
{
|
||||
{
|
||||
Hold_lock hl(this->completed_lock_);
|
||||
|
||||
// There must be something for us to wait for, or we won't
|
||||
// be able to make progress.
|
||||
assert(this->running_ > 0 || !this->completed_.empty());
|
||||
|
||||
if (all_blocked)
|
||||
{
|
||||
this->cleared_blockers_ = 0;
|
||||
this->clear_completed();
|
||||
while (this->cleared_blockers_ == 0)
|
||||
{
|
||||
assert(this->running_ > 0);
|
||||
this->completed_condvar_.wait();
|
||||
this->clear_completed();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this->running_ > 0)
|
||||
{
|
||||
// Wait for a task to finish.
|
||||
this->completed_condvar_.wait();
|
||||
}
|
||||
this->clear_completed();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
Hold_lock hl(this->completed_lock_);
|
||||
|
||||
// If there are no running tasks, then we are done.
|
||||
if (this->running_ == 0)
|
||||
{
|
||||
this->clear_completed();
|
||||
return;
|
||||
}
|
||||
|
||||
// Wait for a task to finish. Then we have to loop around
|
||||
// again in case it added any new tasks before finishing.
|
||||
this->completed_condvar_.wait();
|
||||
this->clear_completed();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Run a task. This is always called in the main thread.
|
||||
|
||||
void
|
||||
Workqueue::run(Task* t)
|
||||
{
|
||||
++this->running_;
|
||||
this->runner_->run(t, t->locks(this));
|
||||
}
|
||||
|
||||
// This is called when a task is completed to put the locks on the
|
||||
// list to be released. We use a list because we only want the locks
|
||||
// to be released in the main thread.
|
||||
|
||||
void
|
||||
Workqueue::completed(Task* t, Task_locker* tl)
|
||||
{
|
||||
{
|
||||
Hold_lock hl(this->completed_lock_);
|
||||
assert(this->running_ > 0);
|
||||
--this->running_;
|
||||
this->completed_.push_back(tl);
|
||||
this->completed_condvar_.signal();
|
||||
}
|
||||
delete t;
|
||||
}
|
||||
|
||||
// This is called when the last task for a blocker has completed.
|
||||
// This is always called in the main thread.
|
||||
|
||||
void
|
||||
Workqueue::cleared_blocker()
|
||||
{
|
||||
++this->cleared_blockers_;
|
||||
}
|
||||
|
||||
} // End namespace gold.
|
|
@ -0,0 +1,336 @@
|
|||
// workqueue.h -- the work queue for gold -*- C++ -*-
|
||||
|
||||
// After processing the command line, everything the linker does is
|
||||
// driven from a work queue. This permits us to parallelize the
|
||||
// linker where possible.
|
||||
|
||||
// Task_token
|
||||
// A simple locking implementation to ensure proper task ordering.
|
||||
// Task_read_token, Task_write_token
|
||||
// Lock a Task_token for read or write.
|
||||
// Task_locker
|
||||
// Task locking using RAII.
|
||||
// Task
|
||||
// An abstract class for jobs to run.
|
||||
|
||||
#ifndef GOLD_WORKQUEUE_H
|
||||
#define GOLD_WORKQUEUE_H
|
||||
|
||||
#include "gold-threads.h"
|
||||
#include "options.h"
|
||||
#include "fileread.h"
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
||||
class Task;
|
||||
class Workqueue;
|
||||
|
||||
// Some tasks require access to shared data structures, such as the
|
||||
// symbol table. Some tasks must be executed in a particular error,
|
||||
// such as reading input file symbol tables--if we see foo.o -llib, we
|
||||
// have to read the symbols for foo.o before we read the ones for
|
||||
// -llib. To implement this safely and efficiently, we use tokens.
|
||||
// Task_tokens support shared read/exclusive write access to some
|
||||
// resource. Alternatively, they support blockers: blockers implement
|
||||
// the requirement that some set of tasks must complete before another
|
||||
// set of tasks can start. In such a case we increment the block
|
||||
// count when we create the task, and decrement it when the task
|
||||
// completes. Task_tokens are only manipulated by the main thread, so
|
||||
// they do not themselves require any locking.
|
||||
|
||||
class Task_token
|
||||
{
|
||||
public:
|
||||
Task_token();
|
||||
|
||||
~Task_token();
|
||||
|
||||
// A read/write token uses these methods.
|
||||
|
||||
bool
|
||||
is_readable() const;
|
||||
|
||||
void
|
||||
add_reader();
|
||||
|
||||
void
|
||||
remove_reader();
|
||||
|
||||
bool
|
||||
is_writable() const;
|
||||
|
||||
void
|
||||
add_writer(const Task*);
|
||||
|
||||
void
|
||||
remove_writer(const Task*);
|
||||
|
||||
bool
|
||||
has_write_lock(const Task*);
|
||||
|
||||
// A blocker token uses these methods.
|
||||
|
||||
void
|
||||
add_blocker();
|
||||
|
||||
// Returns true if block count drops to zero.
|
||||
bool
|
||||
remove_blocker();
|
||||
|
||||
bool
|
||||
is_blocked() const;
|
||||
|
||||
private:
|
||||
// It makes no sense to copy these.
|
||||
Task_token(const Task_token&);
|
||||
Task_token& operator=(const Task_token&);
|
||||
|
||||
bool is_blocker_;
|
||||
int readers_;
|
||||
const Task* writer_;
|
||||
};
|
||||
|
||||
// In order to support tokens more reliably, we provide objects which
|
||||
// handle them using RAII.
|
||||
|
||||
class Task_read_token
|
||||
{
|
||||
public:
|
||||
Task_read_token(Task_token& token)
|
||||
: token_(token)
|
||||
{ this->token_.add_reader(); }
|
||||
|
||||
~Task_read_token()
|
||||
{ this->token_.remove_reader(); }
|
||||
|
||||
private:
|
||||
Task_read_token(const Task_read_token&);
|
||||
Task_read_token& operator=(const Task_read_token&);
|
||||
|
||||
Task_token& token_;
|
||||
};
|
||||
|
||||
class Task_write_token
|
||||
{
|
||||
public:
|
||||
Task_write_token(Task_token& token, const Task* task)
|
||||
: token_(token), task_(task)
|
||||
{ this->token_.add_writer(this->task_); }
|
||||
|
||||
~Task_write_token()
|
||||
{ this->token_.remove_writer(this->task_); }
|
||||
|
||||
private:
|
||||
Task_write_token(const Task_write_token&);
|
||||
Task_write_token& operator=(const Task_write_token&);
|
||||
|
||||
Task_token& token_;
|
||||
const Task* task_;
|
||||
};
|
||||
|
||||
class Task_block_token
|
||||
{
|
||||
public:
|
||||
// The blocker count must be incremented when the task is created.
|
||||
// This object is created when the task is run. When we unblock the
|
||||
// last task, we notify the workqueue.
|
||||
Task_block_token(Task_token& token, Workqueue* workqueue);
|
||||
~Task_block_token();
|
||||
|
||||
private:
|
||||
Task_block_token(const Task_block_token&);
|
||||
Task_block_token& operator=(const Task_block_token&);
|
||||
|
||||
Task_token& token_;
|
||||
Workqueue* workqueue_;
|
||||
};
|
||||
|
||||
// An abstract class used to lock Task_tokens using RAII. A typical
|
||||
// implementation would simply have a set of members of type
|
||||
// Task_read_token, Task_write_token, and Task_block_token.
|
||||
|
||||
class Task_locker
|
||||
{
|
||||
public:
|
||||
Task_locker()
|
||||
{ }
|
||||
|
||||
virtual ~Task_locker()
|
||||
{ }
|
||||
};
|
||||
|
||||
// A version of Task_locker which may be used for a single read lock.
|
||||
|
||||
class Task_locker_read : public Task_locker
|
||||
{
|
||||
public:
|
||||
Task_locker_read(Task_token& token)
|
||||
: read_token_(token)
|
||||
{ }
|
||||
|
||||
private:
|
||||
Task_locker_read(const Task_locker_read&);
|
||||
Task_locker_read& operator=(const Task_locker_read&);
|
||||
|
||||
Task_read_token read_token_;
|
||||
};
|
||||
|
||||
// A version of Task_locker which may be used for a single write lock.
|
||||
|
||||
class Task_locker_write : public Task_locker
|
||||
{
|
||||
public:
|
||||
Task_locker_write(Task_token& token, const Task* task)
|
||||
: write_token_(token, task)
|
||||
{ }
|
||||
|
||||
private:
|
||||
Task_locker_write(const Task_locker_write&);
|
||||
Task_locker_write& operator=(const Task_locker_write&);
|
||||
|
||||
Task_write_token write_token_;
|
||||
};
|
||||
|
||||
// A version of Task_locker which may be used for a single blocker
|
||||
// lock.
|
||||
|
||||
class Task_locker_block : public Task_locker
|
||||
{
|
||||
public:
|
||||
Task_locker_block(Task_token& token, Workqueue* workqueue)
|
||||
: block_token_(token, workqueue)
|
||||
{ }
|
||||
|
||||
private:
|
||||
Task_locker_block(const Task_locker_block&);
|
||||
Task_locker_block& operator=(const Task_locker_block&);
|
||||
|
||||
Task_block_token block_token_;
|
||||
};
|
||||
|
||||
// A version of Task_locker which may be used to hold a lock on a
|
||||
// File_read.
|
||||
|
||||
class Task_locker_file : public Task_locker
|
||||
{
|
||||
public:
|
||||
Task_locker_file(File_read& file)
|
||||
: file_lock_(file)
|
||||
{ }
|
||||
|
||||
private:
|
||||
Task_locker_file(const Task_locker_file&);
|
||||
Task_locker_file& operator=(const Task_locker_file&);
|
||||
|
||||
File_read_lock file_lock_;
|
||||
};
|
||||
|
||||
// The superclass for tasks to be placed on the workqueue. Each
|
||||
// specific task class will inherit from this one.
|
||||
|
||||
class Task
|
||||
{
|
||||
public:
|
||||
Task()
|
||||
{ }
|
||||
virtual ~Task()
|
||||
{ }
|
||||
|
||||
// Type returned by Is_runnable.
|
||||
enum Is_runnable_type
|
||||
{
|
||||
// Task is runnable.
|
||||
IS_RUNNABLE,
|
||||
// Task is waiting for a block to clear.
|
||||
IS_BLOCKED,
|
||||
// Task is not waiting for a block, but is not runnable--i.e., is
|
||||
// waiting for a lock.
|
||||
IS_LOCKED
|
||||
};
|
||||
|
||||
// Return whether the task can be run now. This method is only
|
||||
// called from the main thread.
|
||||
virtual Is_runnable_type
|
||||
is_runnable(Workqueue*) = 0;
|
||||
|
||||
// Return a pointer to a Task_locker which locks all the resources
|
||||
// required by the task. We delete the pointer when the task is
|
||||
// complete. This method can return NULL if no locks are required.
|
||||
// This method is only called from the main thread.
|
||||
virtual Task_locker*
|
||||
locks(Workqueue*) = 0;
|
||||
|
||||
// Run the task.
|
||||
virtual void
|
||||
run(Workqueue*) = 0;
|
||||
};
|
||||
|
||||
// The workqueue
|
||||
|
||||
class Workqueue_runner;
|
||||
|
||||
class Workqueue
|
||||
{
|
||||
public:
|
||||
Workqueue(const General_options&);
|
||||
~Workqueue();
|
||||
|
||||
// Add a new task to the work queue.
|
||||
void
|
||||
queue(Task*);
|
||||
|
||||
// Process all the tasks on the work queue.
|
||||
void
|
||||
process();
|
||||
|
||||
// A complete set of blocking tasks has completed.
|
||||
void
|
||||
cleared_blocker();
|
||||
|
||||
private:
|
||||
// This class can not be copied.
|
||||
Workqueue(const Workqueue&);
|
||||
Workqueue& operator=(const Workqueue&);
|
||||
|
||||
typedef std::list<Task*> Task_list;
|
||||
|
||||
// Run a task.
|
||||
void run(Task*);
|
||||
|
||||
friend class Workqueue_runner;
|
||||
|
||||
// Find a runnable task.
|
||||
Task* find_runnable(Task_list&, bool*);
|
||||
|
||||
// Add a lock to the completed queue.
|
||||
void completed(Task*, Task_locker*);
|
||||
|
||||
// Clear the completed queue.
|
||||
bool clear_completed();
|
||||
|
||||
// How to run a task. Only accessed from main thread.
|
||||
Workqueue_runner* runner_;
|
||||
|
||||
// Lock for access to tasks_ members.
|
||||
Lock tasks_lock_;
|
||||
// List of tasks to execute at each link level.
|
||||
Task_list tasks_;
|
||||
|
||||
// Lock for access to completed_ and running_ members.
|
||||
Lock completed_lock_;
|
||||
// List of Task_locker objects for main thread to free.
|
||||
std::list<Task_locker*> completed_;
|
||||
// Number of tasks currently running.
|
||||
int running_;
|
||||
// Condition variable signalled when a new entry is added to completed_.
|
||||
Condvar completed_condvar_;
|
||||
|
||||
// Number of blocker tokens which were fully cleared. Only accessed
|
||||
// from main thread.
|
||||
int cleared_blockers_;
|
||||
};
|
||||
|
||||
} // End namespace gold.
|
||||
|
||||
#endif // !defined(GOLD_WORKQUEUE_H)
|
Loading…
Reference in New Issue