Skip to content

Commit de96a44

Browse files
committed
Add external import path switch
1 parent 0e5c41f commit de96a44

File tree

13 files changed

+141
-34
lines changed

13 files changed

+141
-34
lines changed

compiler/src/dmd/cli.d

+7-3
Original file line numberDiff line numberDiff line change
@@ -337,11 +337,12 @@ dmd -cov -unittest myprog.d
337337
(only imports).`,
338338
),
339339
Option("dllimport=<value>",
340-
"Windows only: select symbols to dllimport (none/defaultLibsOnly/all)",
341-
`Which global variables to dllimport implicitly if not defined in a root module
340+
"Windows only: select symbols to dllimport (none/defaultLibsOnly/externalOnly/all)",
341+
`Which symbols to dllimport implicitly if not defined in a module that is being compiled
342342
$(UL
343343
$(LI $(I none): None)
344-
$(LI $(I defaultLibsOnly): Only druntime/Phobos symbols)
344+
$(LI $(I defaultLibsOnly): Only druntime/Phobos symbols and any from a module that is marked as external to binary)
345+
$(LI $(I externalOnly): Only symbols found from a module that is marked as external to binary)
345346
$(LI $(I all): All)
346347
)`,
347348
),
@@ -460,6 +461,9 @@ dmd -cov -unittest myprog.d
460461
Option("I=<directory>",
461462
"look for imports also in directory"
462463
),
464+
Option("extI=<directory>",
465+
"look for imports that are out of the currently compiling binary, used to set the module as DllImport"
466+
),
463467
Option("i[=<pattern>]",
464468
"include imported modules in the compilation",
465469
q"{$(P Enables "include imports" mode, where the compiler will include imported

compiler/src/dmd/dmdparams.d

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ enum SymImport : ubyte
3434
{
3535
none, /// no symbols
3636
defaultLibsOnly, /// only druntime/phobos symbols
37+
externalOnly, /// any module that is known to be external to binary (-extI)
3738
all, /// all non-root symbols
3839
}
3940

compiler/src/dmd/dmodule.d

+3
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,8 @@ extern (C++) final class Module : Package
417417
SearchOptFlags searchCacheFlags; // cached flags
418418
bool insearch;
419419

420+
bool isExplicitlyOutOfBinary; // Is this module known to be out of binary, and must be DllImport'd?
421+
420422
/**
421423
* A root module is one that will be compiled all the way to
422424
* object code. This field holds the root module that caused
@@ -536,6 +538,7 @@ extern (C++) final class Module : Package
536538
auto m = new Module(loc, filename, ident, 0, 0);
537539

538540
// TODO: apply import path information (pathInfo) on to module
541+
m.isExplicitlyOutOfBinary = importPathThatFindUs.isOutOfBinary;
539542

540543
if (!m.read(loc))
541544
return null;

compiler/src/dmd/e2ir.d

+86-24
Original file line numberDiff line numberDiff line change
@@ -498,52 +498,114 @@ private __gshared StringTable!(Symbol*) *stringTab;
498498
/*********************************************
499499
* Figure out whether a data symbol should be dllimported
500500
* Params:
501-
* var = declaration of the symbol
501+
* symbl = declaration of the symbol
502502
* Returns:
503503
* true if symbol should be imported from a DLL
504504
*/
505-
bool isDllImported(Dsymbol var)
505+
bool isDllImported(Dsymbol symbl)
506506
{
507+
// Windows is the only platform which dmd supports, that uses the DllImport/DllExport scheme.
507508
if (!(target.os & Target.OS.Windows))
508509
return false;
509-
if (var.isImportedSymbol())
510+
511+
// If function does not have a body, check to see if its marked as DllImport or is set to be exported.
512+
// If a global variable has both export + extern, it is DllImport
513+
if (symbl.isImportedSymbol())
510514
return true;
511-
if (driverParams.symImport == SymImport.none)
512-
return false;
513-
if (auto vd = var.isDeclaration())
515+
516+
// Functions can go through the generated trampoline function.
517+
// Not efficient, but it works.
518+
if (symbl.isFuncDeclaration())
519+
return false; // can always jump through import table
520+
521+
// Global variables are allowed, but not TLS or read only memory.
522+
if (auto vd = symbl.isDeclaration())
523+
{
514524
if (!vd.isDataseg() || vd.isThreadlocal())
515525
return false;
516-
if (var.isFuncDeclaration())
517-
return false; // can always jump through import table
518-
if (auto tid = var.isTypeInfoDeclaration())
526+
}
527+
528+
final switch(driverParams.symImport)
529+
{
530+
case SymImport.none:
531+
// If DllImport overriding is disabled, do not change dllimport status.
532+
return false;
533+
534+
case SymImport.externalOnly:
535+
// Only modules that are marked as out of binary will be DllImport
536+
break;
537+
538+
case SymImport.defaultLibsOnly:
539+
case SymImport.all:
540+
// If to access anything in druntime/phobos you need DllImport, verify against this.
541+
break;
542+
}
543+
const systemLibraryNeedDllImport = driverParams.symImport != SymImport.externalOnly;
544+
545+
// For TypeInfo's check to see if its in druntime and DllImport it
546+
if (auto tid = symbl.isTypeInfoDeclaration())
519547
{
548+
// Built in TypeInfo's are defined in druntime
520549
if (builtinTypeInfo(tid.tinfo))
521-
return true;
550+
return systemLibraryNeedDllImport;
551+
552+
// Convert TypeInfo to its symbol
522553
if (auto ad = isAggregate(tid.type))
523-
var = ad;
554+
symbl = ad;
524555
}
525-
if (driverParams.symImport == SymImport.defaultLibsOnly)
556+
526557
{
527-
auto m = var.getModule();
558+
// Filter the symbol based upon the module it is in.
559+
560+
auto m = symbl.getModule();
528561
if (!m || !m.md)
529562
return false;
530-
const id = m.md.packages.length ? m.md.packages[0] : null;
531-
if (id && id != Id.core && id != Id.std)
532-
return false;
533-
if (!id && m.md.id != Id.std && m.md.id != Id.object)
563+
564+
if (driverParams.symImport == SymImport.all || m.isExplicitlyOutOfBinary)
565+
{
566+
// If a module is specified as being out of binary (-extI), then it is allowed to be DllImport.
567+
}
568+
else if (driverParams.symImport == SymImport.externalOnly)
569+
{
570+
// Module is in binary, therefore not DllImport
534571
return false;
572+
}
573+
else if (systemLibraryNeedDllImport)
574+
{
575+
// Filter out all modules that are not in druntime/phobos if we are only doing default libs only
576+
577+
const id = m.md.packages.length ? m.md.packages[0] : null;
578+
if (id && id != Id.core && id != Id.std)
579+
return false;
580+
if (!id && m.md.id != Id.std && m.md.id != Id.object)
581+
return false;
582+
}
535583
}
536-
else if (driverParams.symImport != SymImport.all)
537-
return false;
538-
if (auto mod = var.isModule())
539-
return !mod.isRoot(); // non-root ModuleInfo symbol
540-
if (var.inNonRoot())
584+
585+
// If symbol is a ModuleInfo, check to see if module is being compiled.
586+
if (auto mod = symbl.isModule())
587+
{
588+
const isBeingCompiled = mod.isRoot();
589+
return !isBeingCompiled; // non-root ModuleInfo symbol
590+
}
591+
592+
// Check to see if a template has been instatiated in current compilation,
593+
// if it is defined in a external module, its DllImport.
594+
if (symbl.inNonRoot())
541595
return true; // not instantiated, and defined in non-root
542-
if (auto ti = var.isInstantiated()) // && !defineOnDeclare(sym, false))
596+
597+
// If a template has been instatiated, only DllImport if it is codegen'ing
598+
if (auto ti = symbl.isInstantiated()) // && !defineOnDeclare(sym, false))
543599
return !ti.needsCodegen(); // instantiated but potentially culled (needsCodegen())
544-
if (auto vd = var.isVarDeclaration())
600+
601+
// If a variable declaration and is extern
602+
if (auto vd = symbl.isVarDeclaration())
603+
{
604+
// Shouldn't this be including an export check too???
545605
if (vd.storage_class & STC.extern_)
546606
return true; // externally defined global variable
607+
}
608+
547609
return false;
548610
}
549611

compiler/src/dmd/frontend.h

+7-3
Original file line numberDiff line numberDiff line change
@@ -7111,6 +7111,7 @@ class Module final : public Package
71117111
Dsymbol* searchCacheSymbol;
71127112
uint32_t searchCacheFlags;
71137113
bool insearch;
7114+
bool isExplicitlyOutOfBinary;
71147115
Module* importedFrom;
71157116
Array<Dsymbol* >* decldefs;
71167117
Array<Module* > aimports;
@@ -8349,12 +8350,15 @@ struct Verbose final
83498350
struct ImportPathInfo final
83508351
{
83518352
const char* path;
8353+
bool isOutOfBinary;
83528354
ImportPathInfo() :
8353-
path()
8355+
path(),
8356+
isOutOfBinary()
83548357
{
83558358
}
8356-
ImportPathInfo(const char* path) :
8357-
path(path)
8359+
ImportPathInfo(const char* path, bool isOutOfBinary = false) :
8360+
path(path),
8361+
isOutOfBinary(isOutOfBinary)
83588362
{}
83598363
};
83608364

compiler/src/dmd/globals.d

+1
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ extern(C++) struct Verbose
153153

154154
extern (C++) struct ImportPathInfo {
155155
const(char)* path; // char*'s of where to look for import modules
156+
bool isOutOfBinary; // Will any module found from this path be out of binary?
156157
}
157158

158159
/// Put command line switches in here

compiler/src/dmd/globals.h

+10-2
Original file line numberDiff line numberDiff line change
@@ -158,9 +158,17 @@ struct Verbose
158158
struct ImportPathInfo
159159
{
160160
const char* path;
161+
d_bool isOutOfBinary;
161162

162-
ImportPathInfo() : path(NULL) { }
163-
ImportPathInfo(const char* p) : path(p) { }
163+
ImportPathInfo() :
164+
path(),
165+
isOutOfBinary()
166+
{
167+
}
168+
ImportPathInfo(const char* path, d_bool isOutOfBinary = false) :
169+
path(path),
170+
isOutOfBinary(isOutOfBinary)
171+
{}
164172
};
165173

166174
// Put command line switches in here

compiler/src/dmd/mars.d

+11-1
Original file line numberDiff line numberDiff line change
@@ -829,11 +829,14 @@ bool parseCommandLine(const ref Strings arguments, const size_t argc, ref Param
829829
case "defaultLibsOnly":
830830
driverParams.symImport = SymImport.defaultLibsOnly;
831831
break;
832+
case "externalOnly":
833+
driverParams.symImport = SymImport.externalOnly;
834+
break;
832835
case "all":
833836
driverParams.symImport = SymImport.all;
834837
break;
835838
default:
836-
error("unknown dllimport '%.*s', must be 'none', 'defaultLibsOnly' or 'all'", cast(int) imp.length, imp.ptr);
839+
error("unknown dllimport '%.*s', must be 'none', 'defaultLibsOnly', 'externalOnly' or 'all'", cast(int) imp.length, imp.ptr);
837840
}
838841
}
839842
else if (arg == "-fIBT")
@@ -1573,6 +1576,13 @@ bool parseCommandLine(const ref Strings arguments, const size_t argc, ref Param
15731576
{
15741577
params.imppath.push(ImportPathInfo(p + 2 + (p[2] == '=')));
15751578
}
1579+
else if (startsWith(p + 1, "extI"))
1580+
{
1581+
// External import path switch -extI
1582+
auto importPathInfo = ImportPathInfo(p + 5 + (p[5] == '='));
1583+
importPathInfo.isOutOfBinary = true;
1584+
params.imppath.push(importPathInfo);
1585+
}
15761586
else if (p[1] == 'm' && p[2] == 'v' && p[3] == '=') // https://dlang.org/dmd.html#switch-mv
15771587
{
15781588
if (p[4] && strchr(p + 5, '='))

compiler/src/dmd/module.h

+2
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ class Module final : public Package
100100
SearchOptFlags searchCacheFlags; // cached flags
101101
d_bool insearch;
102102

103+
d_bool isExplicitlyOutOfBinary; // Is this module known to be out of binary, and must be DllImport'd?
104+
103105
// module from command line we're imported from,
104106
// i.e. a module that will be taken all the
105107
// way to an object file

compiler/test/dshell/dll_cxx.d

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ int main()
4444
// The arguments have to be passed as an array, because run would replace '/' with '\\' otherwise.
4545
run(dllCmd);
4646

47-
run(`$DMD -m$MODEL -g -od=$OUTPUT_BASE -of=$EXE_NAME $SRC/testdll.d ` ~ mainExtra);
47+
run(`$DMD -m$MODEL -g -od=$OUTPUT_BASE -of=$EXE_NAME -extI=$EXTRA_FILES${SEP}dll_cxx${SEP}external $SRC/testdll.d ` ~ mainExtra);
4848

4949
run(`$EXE_NAME`, stdout, stderr, [`LD_LIBRARY_PATH`: Vars.OUTPUT_BASE]);
5050

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module binding;
2+
3+
extern (C) __gshared extern int testExternalImportVar;

compiler/test/dshell/extra-files/dll_cxx/mydll.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,9 @@ EXPORT int getSomeValueCPP19660(void)
7373
{
7474
return someValueCPP19660;
7575
}
76+
77+
extern "C"
78+
{
79+
// tests -extI switch for variables
80+
EXPORT int testExternalImportVar = 0xF1234;
81+
}

compiler/test/dshell/extra-files/dll_cxx/testdll.d

+3
Original file line numberDiff line numberDiff line change
@@ -107,4 +107,7 @@ void main()
107107
{
108108
test22323();
109109
test19660();
110+
111+
import binding;
112+
assert(testExternalImportVar == 0xF1234);
110113
}

0 commit comments

Comments
 (0)