Fix bugzilla 24748 - DMD can't output object files with fully qualified name, making -od overwirte each other file

This commit is contained in:
Dennis Korpel 2024-09-13 15:46:28 +02:00 committed by Nicholas Wilson
parent da9105bc4e
commit 64df340150
9 changed files with 73 additions and 6 deletions

15
changelog/dmd.oq.dd Normal file
View file

@ -0,0 +1,15 @@
Add `-oq` switch to DMD
The switch gives fully qualified names to object files, preventing name conflicts when using the `-od` switch
while compiling multiple modules with the same name, but inside different packages.
The switch already existed in LDC, but is now in dmd as well.
Example:
$(CONSOLE
dmd -c -oq -od=. app.d util/app.d misc/app.d
)
This will output `app.obj`, `util.app.obj`, and `misc.app.obj`, instead of just `app.obj`.
`-oq` also applies to other outputs, such as DDoc (`-D -Dd=.`) and .di header generation (`-H -Hd=.`).

View file

@ -690,6 +690,12 @@ dmd -cov -unittest myprog.d
off when generating an object, interface, or Ddoc file
name. $(SWLINK -op) will leave it on.`,
),
Option("oq",
"Write object files with fully qualified file names",
`When compiling pkg/app.d, the resulting object file name will be pkg_app.obj
instead of app.o. This helps to prevent name conflicts when compiling multiple
packages in the same directory with the $(SWLINK -od) flag.`,
),
Option("os=<os>",
"sets target operating system to <os>",
`Set the target operating system as other than the host.

View file

@ -349,8 +349,8 @@ extern (C++) final class Module : Package
const(char)[] arg; // original argument name
ModuleDeclaration* md; // if !=null, the contents of the ModuleDeclaration declaration
const FileName srcfile; // input source file
const FileName objfile; // output .obj file
const FileName hdrfile; // 'header' file
FileName objfile; // output .obj file
FileName hdrfile; // 'header' file
FileName docfile; // output documentation file
const(ubyte)[] src; /// Raw content of the file
uint errors; // if any errors in file
@ -579,6 +579,22 @@ extern (C++) final class Module : Package
argdoc = arg;
else
argdoc = FileName.name(arg);
if (global.params.fullyQualifiedObjectFiles)
{
const fqn = md ? md.toString() : toString();
argdoc = FileName.replaceName(argdoc, fqn);
// add ext, otherwise forceExt will make nested.module into nested.<ext>
const bufferLength = argdoc.length + 1 + ext.length + /* null terminator */ 1;
char[] s = new char[bufferLength];
s[0 .. argdoc.length] = argdoc[];
s[argdoc.length] = '.';
s[$-1-ext.length .. $-1] = ext[];
s[$-1] = 0;
argdoc = s;
}
// If argdoc doesn't have an absolute path, make it relative to dir
if (!FileName.absolute(argdoc))
{

View file

@ -7020,8 +7020,8 @@ public:
_d_dynamicArray< const char > arg;
ModuleDeclaration* md;
const FileName srcfile;
const FileName objfile;
const FileName hdrfile;
FileName objfile;
FileName hdrfile;
FileName docfile;
_d_dynamicArray< const uint8_t > src;
uint32_t errors;
@ -8112,6 +8112,7 @@ struct Param final
_d_dynamicArray< const char > resfile;
_d_dynamicArray< const char > exefile;
_d_dynamicArray< const char > mapfile;
bool fullyQualifiedObjectFiles;
bool timeTrace;
uint32_t timeTraceGranularityUs;
const char* timeTraceFile;
@ -8191,12 +8192,13 @@ struct Param final
resfile(),
exefile(),
mapfile(),
fullyQualifiedObjectFiles(),
timeTrace(false),
timeTraceGranularityUs(500u),
timeTraceFile()
{
}
Param(bool obj, bool multiobj = false, bool trace = false, bool tracegc = false, bool vcg_ast = false, DiagnosticReporting useDeprecated = (DiagnosticReporting)1u, bool useUnitTests = false, bool useInline = false, bool release = false, bool preservePaths = false, DiagnosticReporting warnings = (DiagnosticReporting)2u, bool cov = false, uint8_t covPercent = 0u, bool ctfe_cov = false, bool ignoreUnsupportedPragmas = true, bool useModuleInfo = true, bool useTypeInfo = true, bool useExceptions = true, bool useGC = true, bool betterC = false, bool addMain = false, bool allInst = false, bool bitfields = false, CppStdRevision cplusplus = (CppStdRevision)201103u, Help help = Help(), Verbose v = Verbose(), FeatureState useDIP25 = (FeatureState)2u, FeatureState useDIP1000 = (FeatureState)0u, bool ehnogc = false, bool useDIP1021 = false, FeatureState fieldwise = (FeatureState)0u, bool fixAliasThis = false, FeatureState rvalueRefParam = (FeatureState)0u, FeatureState noSharedAccess = (FeatureState)0u, bool previewIn = false, bool inclusiveInContracts = false, bool shortenedMethods = true, bool fixImmutableConv = false, bool fix16997 = true, FeatureState dtorFields = (FeatureState)0u, FeatureState systemVariables = (FeatureState)0u, CHECKENABLE useInvariants = (CHECKENABLE)0u, CHECKENABLE useIn = (CHECKENABLE)0u, CHECKENABLE useOut = (CHECKENABLE)0u, CHECKENABLE useArrayBounds = (CHECKENABLE)0u, CHECKENABLE useAssert = (CHECKENABLE)0u, CHECKENABLE useSwitchError = (CHECKENABLE)0u, CHECKENABLE boundscheck = (CHECKENABLE)0u, CHECKACTION checkAction = (CHECKACTION)0u, CLIIdentifierTable dIdentifierTable = (CLIIdentifierTable)0u, CLIIdentifierTable cIdentifierTable = (CLIIdentifierTable)0u, _d_dynamicArray< const char > argv0 = {}, Array<const char* > modFileAliasStrings = Array<const char* >(), Array<const char* > imppath = Array<const char* >(), Array<const char* > fileImppath = Array<const char* >(), _d_dynamicArray< const char > objdir = {}, _d_dynamicArray< const char > objname = {}, _d_dynamicArray< const char > libname = {}, Output ddoc = Output(), Output dihdr = Output(), Output cxxhdr = Output(), Output json = Output(), JsonFieldFlags jsonFieldFlags = (JsonFieldFlags)0u, Output makeDeps = Output(), Output mixinOut = Output(), Output moduleDeps = Output(), uint32_t debuglevel = 0u, uint32_t versionlevel = 0u, bool run = false, Array<const char* > runargs = Array<const char* >(), Array<const char* > cppswitches = Array<const char* >(), const char* cpp = nullptr, Array<const char* > objfiles = Array<const char* >(), Array<const char* > linkswitches = Array<const char* >(), Array<bool > linkswitchIsForCC = Array<bool >(), Array<const char* > libfiles = Array<const char* >(), Array<const char* > dllfiles = Array<const char* >(), _d_dynamicArray< const char > deffile = {}, _d_dynamicArray< const char > resfile = {}, _d_dynamicArray< const char > exefile = {}, _d_dynamicArray< const char > mapfile = {}, bool timeTrace = false, uint32_t timeTraceGranularityUs = 500u, const char* timeTraceFile = nullptr) :
Param(bool obj, bool multiobj = false, bool trace = false, bool tracegc = false, bool vcg_ast = false, DiagnosticReporting useDeprecated = (DiagnosticReporting)1u, bool useUnitTests = false, bool useInline = false, bool release = false, bool preservePaths = false, DiagnosticReporting warnings = (DiagnosticReporting)2u, bool cov = false, uint8_t covPercent = 0u, bool ctfe_cov = false, bool ignoreUnsupportedPragmas = true, bool useModuleInfo = true, bool useTypeInfo = true, bool useExceptions = true, bool useGC = true, bool betterC = false, bool addMain = false, bool allInst = false, bool bitfields = false, CppStdRevision cplusplus = (CppStdRevision)201103u, Help help = Help(), Verbose v = Verbose(), FeatureState useDIP25 = (FeatureState)2u, FeatureState useDIP1000 = (FeatureState)0u, bool ehnogc = false, bool useDIP1021 = false, FeatureState fieldwise = (FeatureState)0u, bool fixAliasThis = false, FeatureState rvalueRefParam = (FeatureState)0u, FeatureState noSharedAccess = (FeatureState)0u, bool previewIn = false, bool inclusiveInContracts = false, bool shortenedMethods = true, bool fixImmutableConv = false, bool fix16997 = true, FeatureState dtorFields = (FeatureState)0u, FeatureState systemVariables = (FeatureState)0u, CHECKENABLE useInvariants = (CHECKENABLE)0u, CHECKENABLE useIn = (CHECKENABLE)0u, CHECKENABLE useOut = (CHECKENABLE)0u, CHECKENABLE useArrayBounds = (CHECKENABLE)0u, CHECKENABLE useAssert = (CHECKENABLE)0u, CHECKENABLE useSwitchError = (CHECKENABLE)0u, CHECKENABLE boundscheck = (CHECKENABLE)0u, CHECKACTION checkAction = (CHECKACTION)0u, CLIIdentifierTable dIdentifierTable = (CLIIdentifierTable)0u, CLIIdentifierTable cIdentifierTable = (CLIIdentifierTable)0u, _d_dynamicArray< const char > argv0 = {}, Array<const char* > modFileAliasStrings = Array<const char* >(), Array<const char* > imppath = Array<const char* >(), Array<const char* > fileImppath = Array<const char* >(), _d_dynamicArray< const char > objdir = {}, _d_dynamicArray< const char > objname = {}, _d_dynamicArray< const char > libname = {}, Output ddoc = Output(), Output dihdr = Output(), Output cxxhdr = Output(), Output json = Output(), JsonFieldFlags jsonFieldFlags = (JsonFieldFlags)0u, Output makeDeps = Output(), Output mixinOut = Output(), Output moduleDeps = Output(), uint32_t debuglevel = 0u, uint32_t versionlevel = 0u, bool run = false, Array<const char* > runargs = Array<const char* >(), Array<const char* > cppswitches = Array<const char* >(), const char* cpp = nullptr, Array<const char* > objfiles = Array<const char* >(), Array<const char* > linkswitches = Array<const char* >(), Array<bool > linkswitchIsForCC = Array<bool >(), Array<const char* > libfiles = Array<const char* >(), Array<const char* > dllfiles = Array<const char* >(), _d_dynamicArray< const char > deffile = {}, _d_dynamicArray< const char > resfile = {}, _d_dynamicArray< const char > exefile = {}, _d_dynamicArray< const char > mapfile = {}, bool fullyQualifiedObjectFiles = false, bool timeTrace = false, uint32_t timeTraceGranularityUs = 500u, const char* timeTraceFile = nullptr) :
obj(obj),
multiobj(multiobj),
trace(trace),
@ -8278,6 +8280,7 @@ struct Param final
resfile(resfile),
exefile(exefile),
mapfile(mapfile),
fullyQualifiedObjectFiles(fullyQualifiedObjectFiles),
timeTrace(timeTrace),
timeTraceGranularityUs(timeTraceGranularityUs),
timeTraceFile(timeTraceFile)

View file

@ -248,6 +248,8 @@ extern (C++) struct Param
const(char)[] exefile;
const(char)[] mapfile;
bool fullyQualifiedObjectFiles; // prepend module names to object files to prevent name conflicts with -od
// Time tracing
bool timeTrace = false; /// Whether profiling of compile time is enabled
uint timeTraceGranularityUs = 500; /// In microseconds, minimum event size to report

View file

@ -250,6 +250,10 @@ struct Param
DString resfile;
DString exefile;
DString mapfile;
bool fullyQualifiedObjectFiles;
bool timeTrace;
uint32_t timeTraceGranularityUs;
const char* timeTraceFile;
};
struct structalign_t

View file

@ -453,6 +453,17 @@ private int tryMain(size_t argc, const(char)** argv, ref Param params)
// m.deleteObjFile();
m.parse();
// Finalize output filenames. Update if `-oq` was specified (only feasible after parsing).
if (params.fullyQualifiedObjectFiles && m.md)
{
m.objfile = m.setOutfilename(params.objname, params.objdir, m.arg, FileName.ext(m.objfile.toString()));
if (m.docfile)
m.setDocfile();
if (m.hdrfile)
m.hdrfile = m.setOutfilename(params.dihdr.name, params.dihdr.dir, m.arg, hdr_ext);
}
if (m.filetype == FileType.dhdr)
{
// Remove m's object file from list of object files

View file

@ -1286,6 +1286,11 @@ bool parseCommandLine(const ref Strings arguments, const size_t argc, ref Param
goto Lerror;
params.preservePaths = true;
break;
case 'q':
if (p[3])
goto Lerror;
params.fullyQualifiedObjectFiles = true;
break;
case 0:
error("-o no longer supported, use -of or -od");
break;

View file

@ -14,6 +14,7 @@
# -Xf=<filename>
src_file=${OUTPUT_BASE}/src.d
src_file_in_pkg=${OUTPUT_BASE}/pkg/src.d
clean()
{
@ -26,6 +27,8 @@ prepare()
mkdir -p ${OUTPUT_BASE}
echo "module mymod;" > ${OUTPUT_BASE}/mymod.d
echo "module src; import mymod;" > ${src_file}
mkdir ${OUTPUT_BASE}/pkg
echo "module pkg.src;" > ${src_file_in_pkg}
}
die()
@ -59,7 +62,9 @@ $DMD -o- -od=${OUTPUT_BASE} -D -Df=${OUTPUT_BASE}/src.html -Hf=${OUTPUT_BASE}/sr
checkFiles;
prepare;
$DMD -o- -od=${OUTPUT_BASE} -D -Dd=${OUTPUT_BASE} -Hd=${OUTPUT_BASE} -I=${OUTPUT_BASE} -L=-v -Xf=${OUTPUT_BASE}/json.json ${src_file}
$DMD -o- -oq -od=${OUTPUT_BASE} -D -Dd=${OUTPUT_BASE} -Hd=${OUTPUT_BASE} -I=${OUTPUT_BASE} -L=-v -Xf=${OUTPUT_BASE}/json.json ${src_file} ${src_file_in_pkg}
checkFiles;
checkFile ${OUTPUT_BASE}/pkg.src.di
checkFile ${OUTPUT_BASE}/pkg.src.html
clean;