Don't reverse order of object file names

Make sure the overall order corresponds to the user's command-line order
of object and source files. The only exception being singleObj builds,
for which the single object file for all source files is always the first
entry in the object files list (which is forwarded to the linker in that
order). This is done so that we can easily get hold of the name when
emitting the single object file later in the `ldc::CodeGenerator` dtor.
It should also clearly define the linking order (affecting comdat
selections etc.) for special singleObj builds.

Also reuse some more code (wrt. output filenames) from DMD's main().
This commit is contained in:
Martin 2016-09-17 22:42:50 +02:00
parent 1c82c405d6
commit b1a6315ee4
7 changed files with 96 additions and 97 deletions

View file

@ -154,6 +154,7 @@ version(IN_LLVM)
void genCmain(Scope* sc);
// in driver/main.cpp
void addDefaultVersionIdentifiers();
void codegenModules(ref Modules modules);
// in driver/linker.cpp
int linkObjToBinary();
@ -1102,6 +1103,14 @@ Language changes listed by -transition=id:
global.params.useAssert = true;
if (!global.params.obj || global.params.lib)
global.params.link = false;
return mars_mainBody(files, libmodules);
}
} // !IN_LLVM
extern (C++) int mars_mainBody(ref Strings files, ref Strings libmodules)
{
if (global.params.link)
{
global.params.exefile = global.params.objname;
@ -1131,10 +1140,13 @@ Language changes listed by -transition=id:
{
global.params.libname = global.params.objname;
global.params.objname = null;
version (IN_LLVM) {} else
{
// Haven't investigated handling these options with multiobj
if (!global.params.cov && !global.params.trace)
global.params.multiobj = true;
}
}
else
{
if (global.params.objname && files.dim > 1)
@ -1147,17 +1159,13 @@ Language changes listed by -transition=id:
// Predefined version identifiers
addDefaultVersionIdentifiers();
version (IN_LLVM) {} else
{
objc_tryMain_dObjc();
setDefaultLibrary();
return mars_mainBody(files, libmodules);
}
} // !IN_LLVM
extern (C++) int mars_mainBody(ref Strings files, ref Strings libmodules)
{
// Initialization
Type._init();
Id.initialize();
@ -1214,7 +1222,14 @@ extern (C++) int mars_mainBody(ref Strings files, ref Strings libmodules)
// Create Modules
Modules modules;
modules.reserve(files.dim);
version (IN_LLVM)
{
size_t firstModuleObjectFileIndex = size_t.max;
}
else
{
bool firstmodule = true;
}
for (size_t i = 0; i < files.dim; i++)
{
const(char)* name;
@ -1337,7 +1352,23 @@ extern (C++) int mars_mainBody(ref Strings files, ref Strings libmodules)
auto id = Identifier.idPool(name, strlen(name));
auto m = new Module(files[i], id, global.params.doDocComments, global.params.doHdrGeneration);
modules.push(m);
version (IN_LLVM) {} else
version (IN_LLVM)
{
// If `-run` is passed, the obj file is temporary and is removed after execution.
// Make sure the name does not collide with other files from other processes by
// creating a unique filename.
if (global.params.run)
m.makeObjectFilenameUnique();
if (!global.params.oneobj || firstModuleObjectFileIndex == size_t.max)
{
global.params.objfiles.push(m.objfile.name.str);
m.checkAndAddOutputFile(m.objfile);
if (firstModuleObjectFileIndex == size_t.max)
firstModuleObjectFileIndex = global.params.objfiles.dim - 1;
}
}
else
{
if (firstmodule)
{
@ -1346,6 +1377,19 @@ extern (C++) int mars_mainBody(ref Strings files, ref Strings libmodules)
}
}
}
version (IN_LLVM)
{
if (global.params.oneobj && modules.dim < 2)
global.params.oneobj = false;
// global.params.oneobj => move object file for first source file to
// beginning of object files list
if (global.params.oneobj && firstModuleObjectFileIndex != 0)
{
auto fn = (*global.params.objfiles)[firstModuleObjectFileIndex];
global.params.objfiles.remove(firstModuleObjectFileIndex);
global.params.objfiles.insert(0, fn);
}
}
// Read files
/* Start by "reading" the dummy main.d file
*/
@ -1612,22 +1656,6 @@ extern (C++) int mars_mainBody(ref Strings files, ref Strings libmodules)
}
version (IN_LLVM)
{
for (size_t i = 0; i < modules.dim; i++)
{
Module m = modules[i];
if (!m.objfile)
continue;
// If `-run` is passed, the obj file is temporary and is removed after execution.
// Make sure the name does not collide with other files from other processes by
// creating a unique filename.
if (global.params.run)
m.makeObjectFilenameUnique();
if (!global.params.oneobj || i == 0)
m.checkAndAddOutputFile(m.objfile);
}
codegenModules(modules);
}
else
@ -1959,6 +1987,9 @@ extern (C++) Expressions* Expressions_create()
return new Expressions();
}
version (IN_LLVM) {} else
{
/**
* Set the default and debug libraries to link against, if not already set
*
@ -2110,3 +2141,5 @@ private void addDefaultVersionIdentifiers()
VersionCondition.addPredefinedGlobalIdent("D_NoBoundsChecks");
VersionCondition.addPredefinedGlobalIdent("D_HardFloat");
}
} // !IN_LLVM

View file

@ -77,8 +77,7 @@ void emitLinkerOptions(IRState &irs, llvm::Module &M, llvm::LLVMContext &ctx) {
namespace ldc {
CodeGenerator::CodeGenerator(llvm::LLVMContext &context, bool singleObj)
: context_(context), moduleCount_(0), singleObj_(singleObj), ir_(nullptr),
firstModuleObjfileName_(nullptr) {
: context_(context), moduleCount_(0), singleObj_(singleObj), ir_(nullptr) {
if (!ClassDeclaration::object) {
error(Loc(), "declaration for class Object not found; druntime not "
"configured properly");
@ -95,17 +94,9 @@ CodeGenerator::CodeGenerator(llvm::LLVMContext &context, bool singleObj)
CodeGenerator::~CodeGenerator() {
if (singleObj_) {
const char *oname;
const char *filename;
if ((oname = global.params.exefile) || (oname = global.params.objname)) {
filename = FileName::forceExt(oname, global.obj_ext);
if (global.params.objdir) {
filename =
FileName::combine(global.params.objdir, FileName::name(filename));
}
} else {
filename = firstModuleObjfileName_;
}
// For singleObj builds, the first object file name is the one for the first
// source file (e.g., `b.o` for `ldc2 a.o b.d c.d`).
const char *filename = (*global.params.objfiles)[0];
// If there are bitcode files passed on the cmdline, add them after all
// other source files have been added to the (singleobj) module.
@ -117,9 +108,6 @@ CodeGenerator::~CodeGenerator() {
}
void CodeGenerator::prepareLLModule(Module *m) {
if (!firstModuleObjfileName_) {
firstModuleObjfileName_ = m->objfile->name->str;
}
++moduleCount_;
if (singleObj_ && ir_) {
@ -181,7 +169,6 @@ void CodeGenerator::writeAndFreeLLModule(const char *filename) {
IdentMetadata->addOperand(llvm::MDNode::get(ir_->context(), IdentNode));
writeModule(&ir_->module, filename);
global.params.objfiles->push(const_cast<char *>(filename));
delete ir_;
ir_ = nullptr;
}

View file

@ -39,7 +39,6 @@ private:
int moduleCount_;
bool const singleObj_;
IRState *ir_;
const char *firstModuleObjfileName_;
};
}

View file

@ -149,10 +149,8 @@ static int linkObjToBinaryGcc(bool sharedLib, bool fullyStatic) {
std::vector<std::string> args;
// object files
for (unsigned i = 0; i < global.params.objfiles->dim; i++) {
const char *p = static_cast<const char *>(global.params.objfiles->data[i]);
args.push_back(p);
}
for (unsigned i = 0; i < global.params.objfiles->dim; i++)
args.push_back((*global.params.objfiles)[i]);
// Link with profile-rt library when generating an instrumented binary.
// profile-rt uses Phobos (MD5 hashing) and therefore must be passed on the
@ -170,10 +168,8 @@ static int linkObjToBinaryGcc(bool sharedLib, bool fullyStatic) {
}
// user libs
for (unsigned i = 0; i < global.params.libfiles->dim; i++) {
const char *p = static_cast<const char *>(global.params.libfiles->data[i]);
args.push_back(p);
}
for (unsigned i = 0; i < global.params.libfiles->dim; i++)
args.push_back((*global.params.libfiles)[i]);
// output filename
std::string output = getOutputName(sharedLib);
@ -211,8 +207,7 @@ static int linkObjToBinaryGcc(bool sharedLib, bool fullyStatic) {
// additional linker switches
for (unsigned i = 0; i < global.params.linkswitches->dim; i++) {
const char *p =
static_cast<const char *>(global.params.linkswitches->data[i]);
const char *p = (*global.params.linkswitches)[i];
// Don't push -l and -L switches using -Xlinker, but pass them indirectly
// via GCC. This makes sure user-defined paths take precedence over
// GCC's builtin LIBRARY_PATHs.
@ -598,10 +593,8 @@ static int linkObjToBinaryWin(bool sharedLib) {
args.push_back("/OUT:" + output);
// object files
for (unsigned i = 0; i < global.params.objfiles->dim; i++) {
const char *p = static_cast<const char *>(global.params.objfiles->data[i]);
args.push_back(p);
}
for (unsigned i = 0; i < global.params.objfiles->dim; i++)
args.push_back((*global.params.objfiles)[i]);
// Link with profile-rt library when generating an instrumented binary
// profile-rt depends on Phobos (MD5 hashing).
@ -612,10 +605,8 @@ static int linkObjToBinaryWin(bool sharedLib) {
}
// user libs
for (unsigned i = 0; i < global.params.libfiles->dim; i++) {
const char *p = static_cast<const char *>(global.params.libfiles->data[i]);
args.push_back(p);
}
for (unsigned i = 0; i < global.params.libfiles->dim; i++)
args.push_back((*global.params.libfiles)[i]);
// set the global gExePath
gExePath = output;

View file

@ -658,37 +658,6 @@ void parseCommandLine(int argc, char **argv, Strings &sourceFiles,
mRelocModel = llvm::Reloc::PIC_;
}
if (global.params.link) {
global.params.exefile = global.params.objname;
global.params.oneobj = true;
if (global.params.objname) {
/* Use this to name the one object file with the same
* name as the exe file.
*/
global.params.objname =
FileName::forceExt(global.params.objname, global.obj_ext);
/* If output directory is given, use that path rather than
* the exe file path.
*/
if (global.params.objdir) {
const char *name = FileName::name(global.params.objname);
global.params.objname = FileName::combine(global.params.objdir, name);
}
}
} else if (global.params.run) {
error(Loc(), "flags conflict with -run");
fatal();
} else if (global.params.lib) {
global.params.libname = global.params.objname;
global.params.objname = nullptr;
} else {
if (global.params.objname && sourceFiles.dim > 1) {
global.params.oneobj = true;
// error("multiple source files, but only one .obj name");
// fatal();
}
}
if (soname.getNumOccurrences() > 0 && !global.params.dll) {
error(Loc(), "-soname can be used only when building a shared library");
}
@ -1130,14 +1099,9 @@ int cppmain(int argc, char **argv) {
// allocate the target abi
gABI = TargetABI::getTarget();
// Set predefined version identifiers.
registerPredefinedVersions();
dumpPredefinedVersions();
if (global.params.targetTriple->isOSWindows()) {
global.dll_ext = "dll";
global.lib_ext =
(global.params.targetTriple->isWindowsMSVCEnvironment() ? "lib" : "a");
global.lib_ext = (global.params.mscoff ? "lib" : "a");
} else {
global.dll_ext = "so";
global.lib_ext = "a";
@ -1147,6 +1111,11 @@ int cppmain(int argc, char **argv) {
return mars_mainBody(files, libmodules);
}
void addDefaultVersionIdentifiers() {
registerPredefinedVersions();
dumpPredefinedVersions();
}
void codegenModules(Modules &modules) {
// Generate one or more object/IR/bitcode files.
if (global.params.obj && !modules.empty()) {

View file

@ -0,0 +1,19 @@
// Make sure the inferred output filename is based on the first (source or
// object) file, and independent from its module declaration.
// If it works on Windows, it will work on other platforms too, and it
// simplifies things a bit.
// REQUIRES: Windows
// 1) 2 object files compiled separately:
// RUN: %ldc -c %S/inputs/foo.d -of=%T/foo%obj
// RUN: %ldc %s %T/foo%obj -vv | FileCheck %s
// 2) singleObj build with external object file and 2 source files:
// RUN: %ldc %T/foo%obj %s %S/inputs/attr_weak_input.d -vv | FileCheck %s
// CHECK: Linking with:
// CHECK-NEXT: '/OUT:inferred_outputname.exe'
module modulename;
void main() {}

View file

@ -0,0 +1 @@
void bar() {}