mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-09 20:37:25 +03:00
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:
parent
1c82c405d6
commit
b1a6315ee4
7 changed files with 96 additions and 97 deletions
81
ddmd/mars.d
81
ddmd/mars.d
|
@ -154,6 +154,7 @@ version(IN_LLVM)
|
||||||
|
|
||||||
void genCmain(Scope* sc);
|
void genCmain(Scope* sc);
|
||||||
// in driver/main.cpp
|
// in driver/main.cpp
|
||||||
|
void addDefaultVersionIdentifiers();
|
||||||
void codegenModules(ref Modules modules);
|
void codegenModules(ref Modules modules);
|
||||||
// in driver/linker.cpp
|
// in driver/linker.cpp
|
||||||
int linkObjToBinary();
|
int linkObjToBinary();
|
||||||
|
@ -1102,6 +1103,14 @@ Language changes listed by -transition=id:
|
||||||
global.params.useAssert = true;
|
global.params.useAssert = true;
|
||||||
if (!global.params.obj || global.params.lib)
|
if (!global.params.obj || global.params.lib)
|
||||||
global.params.link = false;
|
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)
|
if (global.params.link)
|
||||||
{
|
{
|
||||||
global.params.exefile = global.params.objname;
|
global.params.exefile = global.params.objname;
|
||||||
|
@ -1131,10 +1140,13 @@ Language changes listed by -transition=id:
|
||||||
{
|
{
|
||||||
global.params.libname = global.params.objname;
|
global.params.libname = global.params.objname;
|
||||||
global.params.objname = null;
|
global.params.objname = null;
|
||||||
|
version (IN_LLVM) {} else
|
||||||
|
{
|
||||||
// Haven't investigated handling these options with multiobj
|
// Haven't investigated handling these options with multiobj
|
||||||
if (!global.params.cov && !global.params.trace)
|
if (!global.params.cov && !global.params.trace)
|
||||||
global.params.multiobj = true;
|
global.params.multiobj = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (global.params.objname && files.dim > 1)
|
if (global.params.objname && files.dim > 1)
|
||||||
|
@ -1147,17 +1159,13 @@ Language changes listed by -transition=id:
|
||||||
|
|
||||||
// Predefined version identifiers
|
// Predefined version identifiers
|
||||||
addDefaultVersionIdentifiers();
|
addDefaultVersionIdentifiers();
|
||||||
|
version (IN_LLVM) {} else
|
||||||
|
{
|
||||||
objc_tryMain_dObjc();
|
objc_tryMain_dObjc();
|
||||||
|
|
||||||
setDefaultLibrary();
|
setDefaultLibrary();
|
||||||
|
}
|
||||||
|
|
||||||
return mars_mainBody(files, libmodules);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // !IN_LLVM
|
|
||||||
|
|
||||||
extern (C++) int mars_mainBody(ref Strings files, ref Strings libmodules)
|
|
||||||
{
|
|
||||||
// Initialization
|
// Initialization
|
||||||
Type._init();
|
Type._init();
|
||||||
Id.initialize();
|
Id.initialize();
|
||||||
|
@ -1214,7 +1222,14 @@ extern (C++) int mars_mainBody(ref Strings files, ref Strings libmodules)
|
||||||
// Create Modules
|
// Create Modules
|
||||||
Modules modules;
|
Modules modules;
|
||||||
modules.reserve(files.dim);
|
modules.reserve(files.dim);
|
||||||
|
version (IN_LLVM)
|
||||||
|
{
|
||||||
|
size_t firstModuleObjectFileIndex = size_t.max;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
bool firstmodule = true;
|
bool firstmodule = true;
|
||||||
|
}
|
||||||
for (size_t i = 0; i < files.dim; i++)
|
for (size_t i = 0; i < files.dim; i++)
|
||||||
{
|
{
|
||||||
const(char)* name;
|
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 id = Identifier.idPool(name, strlen(name));
|
||||||
auto m = new Module(files[i], id, global.params.doDocComments, global.params.doHdrGeneration);
|
auto m = new Module(files[i], id, global.params.doDocComments, global.params.doHdrGeneration);
|
||||||
modules.push(m);
|
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)
|
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
|
// Read files
|
||||||
/* Start by "reading" the dummy main.d file
|
/* 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)
|
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);
|
codegenModules(modules);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1959,6 +1987,9 @@ extern (C++) Expressions* Expressions_create()
|
||||||
return new Expressions();
|
return new Expressions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
version (IN_LLVM) {} else
|
||||||
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the default and debug libraries to link against, if not already set
|
* 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_NoBoundsChecks");
|
||||||
VersionCondition.addPredefinedGlobalIdent("D_HardFloat");
|
VersionCondition.addPredefinedGlobalIdent("D_HardFloat");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // !IN_LLVM
|
||||||
|
|
|
@ -77,8 +77,7 @@ void emitLinkerOptions(IRState &irs, llvm::Module &M, llvm::LLVMContext &ctx) {
|
||||||
|
|
||||||
namespace ldc {
|
namespace ldc {
|
||||||
CodeGenerator::CodeGenerator(llvm::LLVMContext &context, bool singleObj)
|
CodeGenerator::CodeGenerator(llvm::LLVMContext &context, bool singleObj)
|
||||||
: context_(context), moduleCount_(0), singleObj_(singleObj), ir_(nullptr),
|
: context_(context), moduleCount_(0), singleObj_(singleObj), ir_(nullptr) {
|
||||||
firstModuleObjfileName_(nullptr) {
|
|
||||||
if (!ClassDeclaration::object) {
|
if (!ClassDeclaration::object) {
|
||||||
error(Loc(), "declaration for class Object not found; druntime not "
|
error(Loc(), "declaration for class Object not found; druntime not "
|
||||||
"configured properly");
|
"configured properly");
|
||||||
|
@ -95,17 +94,9 @@ CodeGenerator::CodeGenerator(llvm::LLVMContext &context, bool singleObj)
|
||||||
|
|
||||||
CodeGenerator::~CodeGenerator() {
|
CodeGenerator::~CodeGenerator() {
|
||||||
if (singleObj_) {
|
if (singleObj_) {
|
||||||
const char *oname;
|
// For singleObj builds, the first object file name is the one for the first
|
||||||
const char *filename;
|
// source file (e.g., `b.o` for `ldc2 a.o b.d c.d`).
|
||||||
if ((oname = global.params.exefile) || (oname = global.params.objname)) {
|
const char *filename = (*global.params.objfiles)[0];
|
||||||
filename = FileName::forceExt(oname, global.obj_ext);
|
|
||||||
if (global.params.objdir) {
|
|
||||||
filename =
|
|
||||||
FileName::combine(global.params.objdir, FileName::name(filename));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
filename = firstModuleObjfileName_;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there are bitcode files passed on the cmdline, add them after all
|
// If there are bitcode files passed on the cmdline, add them after all
|
||||||
// other source files have been added to the (singleobj) module.
|
// other source files have been added to the (singleobj) module.
|
||||||
|
@ -117,9 +108,6 @@ CodeGenerator::~CodeGenerator() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeGenerator::prepareLLModule(Module *m) {
|
void CodeGenerator::prepareLLModule(Module *m) {
|
||||||
if (!firstModuleObjfileName_) {
|
|
||||||
firstModuleObjfileName_ = m->objfile->name->str;
|
|
||||||
}
|
|
||||||
++moduleCount_;
|
++moduleCount_;
|
||||||
|
|
||||||
if (singleObj_ && ir_) {
|
if (singleObj_ && ir_) {
|
||||||
|
@ -181,7 +169,6 @@ void CodeGenerator::writeAndFreeLLModule(const char *filename) {
|
||||||
IdentMetadata->addOperand(llvm::MDNode::get(ir_->context(), IdentNode));
|
IdentMetadata->addOperand(llvm::MDNode::get(ir_->context(), IdentNode));
|
||||||
|
|
||||||
writeModule(&ir_->module, filename);
|
writeModule(&ir_->module, filename);
|
||||||
global.params.objfiles->push(const_cast<char *>(filename));
|
|
||||||
delete ir_;
|
delete ir_;
|
||||||
ir_ = nullptr;
|
ir_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,6 @@ private:
|
||||||
int moduleCount_;
|
int moduleCount_;
|
||||||
bool const singleObj_;
|
bool const singleObj_;
|
||||||
IRState *ir_;
|
IRState *ir_;
|
||||||
const char *firstModuleObjfileName_;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -149,10 +149,8 @@ static int linkObjToBinaryGcc(bool sharedLib, bool fullyStatic) {
|
||||||
std::vector<std::string> args;
|
std::vector<std::string> args;
|
||||||
|
|
||||||
// object files
|
// object files
|
||||||
for (unsigned i = 0; i < global.params.objfiles->dim; i++) {
|
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((*global.params.objfiles)[i]);
|
||||||
args.push_back(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Link with profile-rt library when generating an instrumented binary.
|
// Link with profile-rt library when generating an instrumented binary.
|
||||||
// profile-rt uses Phobos (MD5 hashing) and therefore must be passed on the
|
// 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
|
// user libs
|
||||||
for (unsigned i = 0; i < global.params.libfiles->dim; i++) {
|
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((*global.params.libfiles)[i]);
|
||||||
args.push_back(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
// output filename
|
// output filename
|
||||||
std::string output = getOutputName(sharedLib);
|
std::string output = getOutputName(sharedLib);
|
||||||
|
@ -211,8 +207,7 @@ static int linkObjToBinaryGcc(bool sharedLib, bool fullyStatic) {
|
||||||
|
|
||||||
// additional linker switches
|
// additional linker switches
|
||||||
for (unsigned i = 0; i < global.params.linkswitches->dim; i++) {
|
for (unsigned i = 0; i < global.params.linkswitches->dim; i++) {
|
||||||
const char *p =
|
const char *p = (*global.params.linkswitches)[i];
|
||||||
static_cast<const char *>(global.params.linkswitches->data[i]);
|
|
||||||
// Don't push -l and -L switches using -Xlinker, but pass them indirectly
|
// Don't push -l and -L switches using -Xlinker, but pass them indirectly
|
||||||
// via GCC. This makes sure user-defined paths take precedence over
|
// via GCC. This makes sure user-defined paths take precedence over
|
||||||
// GCC's builtin LIBRARY_PATHs.
|
// GCC's builtin LIBRARY_PATHs.
|
||||||
|
@ -598,10 +593,8 @@ static int linkObjToBinaryWin(bool sharedLib) {
|
||||||
args.push_back("/OUT:" + output);
|
args.push_back("/OUT:" + output);
|
||||||
|
|
||||||
// object files
|
// object files
|
||||||
for (unsigned i = 0; i < global.params.objfiles->dim; i++) {
|
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((*global.params.objfiles)[i]);
|
||||||
args.push_back(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Link with profile-rt library when generating an instrumented binary
|
// Link with profile-rt library when generating an instrumented binary
|
||||||
// profile-rt depends on Phobos (MD5 hashing).
|
// profile-rt depends on Phobos (MD5 hashing).
|
||||||
|
@ -612,10 +605,8 @@ static int linkObjToBinaryWin(bool sharedLib) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// user libs
|
// user libs
|
||||||
for (unsigned i = 0; i < global.params.libfiles->dim; i++) {
|
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((*global.params.libfiles)[i]);
|
||||||
args.push_back(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
// set the global gExePath
|
// set the global gExePath
|
||||||
gExePath = output;
|
gExePath = output;
|
||||||
|
|
|
@ -658,37 +658,6 @@ void parseCommandLine(int argc, char **argv, Strings &sourceFiles,
|
||||||
mRelocModel = llvm::Reloc::PIC_;
|
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) {
|
if (soname.getNumOccurrences() > 0 && !global.params.dll) {
|
||||||
error(Loc(), "-soname can be used only when building a shared library");
|
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
|
// allocate the target abi
|
||||||
gABI = TargetABI::getTarget();
|
gABI = TargetABI::getTarget();
|
||||||
|
|
||||||
// Set predefined version identifiers.
|
|
||||||
registerPredefinedVersions();
|
|
||||||
dumpPredefinedVersions();
|
|
||||||
|
|
||||||
if (global.params.targetTriple->isOSWindows()) {
|
if (global.params.targetTriple->isOSWindows()) {
|
||||||
global.dll_ext = "dll";
|
global.dll_ext = "dll";
|
||||||
global.lib_ext =
|
global.lib_ext = (global.params.mscoff ? "lib" : "a");
|
||||||
(global.params.targetTriple->isWindowsMSVCEnvironment() ? "lib" : "a");
|
|
||||||
} else {
|
} else {
|
||||||
global.dll_ext = "so";
|
global.dll_ext = "so";
|
||||||
global.lib_ext = "a";
|
global.lib_ext = "a";
|
||||||
|
@ -1147,6 +1111,11 @@ int cppmain(int argc, char **argv) {
|
||||||
return mars_mainBody(files, libmodules);
|
return mars_mainBody(files, libmodules);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void addDefaultVersionIdentifiers() {
|
||||||
|
registerPredefinedVersions();
|
||||||
|
dumpPredefinedVersions();
|
||||||
|
}
|
||||||
|
|
||||||
void codegenModules(Modules &modules) {
|
void codegenModules(Modules &modules) {
|
||||||
// Generate one or more object/IR/bitcode files.
|
// Generate one or more object/IR/bitcode files.
|
||||||
if (global.params.obj && !modules.empty()) {
|
if (global.params.obj && !modules.empty()) {
|
||||||
|
|
19
tests/codegen/inferred_outputname.d
Normal file
19
tests/codegen/inferred_outputname.d
Normal 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() {}
|
1
tests/codegen/inputs/foo.d
Normal file
1
tests/codegen/inputs/foo.d
Normal file
|
@ -0,0 +1 @@
|
||||||
|
void bar() {}
|
Loading…
Add table
Add a link
Reference in a new issue