-
-
Notifications
You must be signed in to change notification settings - Fork 609
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add __traits(getCmdlineConstant) #15257
Conversation
Thanks for your pull request and interest in making D better, @ErnyTech! We are looking forward to reviewing it, and you should be hearing from a maintainer soon.
Please see CONTRIBUTING.md for more information. If you have addressed all reviews or aren't sure how to proceed, don't hesitate to ping us with a simple comment. Bugzilla referencesYour PR doesn't reference any Bugzilla issue. If your PR contains non-trivial changes, please reference a Bugzilla issue or create a manual changelog. Testing this PR locallyIf you don't have a local development environment setup, you can use Digger to test this PR: dub run digger -- build "master + dmd#15257" |
I've been thinking a bit about configuration files instead of just a command-line argument. But that can be handled with a build manager like dub pretty easily. For this reason, I don't like calling it a command line constant because it may be backed by something else. There is also some concern about long command lines, which is where a configuration file instead would be a better option. I suspect there is some design work left to make this more compelling, but otherwise a nice idea. |
This is a good argument, I'm not sure what the best name for it was for now I could think of:
Other name ideas are welcome :-)
I don't see this as a big deal because I imagine uses of this feature are done in projects that use build systems eg dub, cmake, makefile so command length isn't a real issue
Yes this is only necessary to introduce the concept in D, then it would be useful to add a convenient interface to use in dub to define the configuration and probably also some helpers in the std to make the most common uses more comfortable. I'm trying to do this by minimizing language changes (just a new traits) and compiler then allowing usages to expand outside the language spec and DMD
If this PR is merged, they can be implemented in DUB. I think it's better than introducing the need for the compiler to parse configuration files that probably should be defined in the language specification while with my solution the only change to the language is the new traits and the parameter to pass to the compiler is actually a implementation-defined In any case, this PR is currently a draft, any advice to improve it would be welcome ;-) |
It is. We've had a number of issues over the years regarding it in dub. The general solution is to use a file to put the arguments in and pass that to the compiler, but unfortunately, that hasn't been 100%. |
Oh I've never seen this, can you send me a reference so I can learn? Thank you for your feedback |
Here are 4 although they appear to all be fixed by the same PR. |
As far as I can tell this is caused by the MS Linker, so a long command with -define shouldn't cause any problems |
I think this is very useful addition to the compiler -> language interface! This lack of this functionality has necessitated lots of awkward workarounds in our ecosystem, usually requiring external build tools, for something that the compiler can handle by itself in a more ergonomic way. At work we have a couple of Nim projects which is how I learned about the their
And especially this: nim c -d:FooBar=42 foobar.nim const FooBar {.intdefine.}: int = 5 If There a few things that we can do better:
For example, for Phobos I'd like to be able to do the following:
Which would translate into: enum defaultTZDatabaseDir = "/nix/store/w2swil1dw4fxmvkggcik4l0jiywwp5vp-tzdata-2022g/share/zoneinfo"; Or more generally, the syntax of the switch should be: |
I'm currently working on this
I'm a bit skeptical about this, it risks causing confusion. Perhaps it would be better to add an optional parameter to traits to request evaluation at compile time |
Attempting to tokenize it first (to get a single token out of it like a float), would be ok. If it fails fall back to string. But yeah an expression is more dodgy. |
The problem is a user could pass a string which could be evaluated as an integer, for example Obviously we could force the user to specify the string like this |
Yeah this could be configurable using a bool argument to the trait. No reason to not offer that override. |
Regarding arbitrary expressions, here's one use case:
Obviously, this can be accomplished even if the compiler supported only passing strings, e.g.: module app_version;
enum currentVersion = parseSemVer(__traits(getCmdlineConstant, "version")); But the ability to pass expressions feels more ergonomic to me. |
PR Updates:
Thanks to @rikkimax and @PetarKirov who helped me with feedback to try and improve PR |
all of those are problems with windows' file path length limit, nothing to do with command line length limits. |
This will introduce a solution similar in concept to the preprocessor macros commonly used in C/C++, but adapted to D which has no preprocessor. In particular, allowing you to define a compile time constants by passing them to the compiler as a parameter. Since that D doesn't have a preprocessor, I think the most elegant way to introduce a "global" constants, avoiding creating unwanted conflicts with code, is to introduce a traits capable of obtaining the constants defined via parameters passed to the compiler. Currently some D-projects (including DMD itself, see https://github.com/dlang/dmd/blob/03ee26acb162dc92abf3ea1b9fc8e6296bb3eaa9/compiler/src/dmd/dinifile.d#L103) try to sort of have constants defined at compiler params by writing the value to a file and then using ImportExpression, however I think this method is very inconvenient and introducing this new solution is simpler and more elegant. Example code: module mymod; pragma(msg, __traits(getCmdlineConstant, "test1")); pragma(msg, __traits(getCmdlineConstant, "test2", false, "default")); Compiling with the parameters "-define:mymod.test1=dlang" will return the following messages "dlang" and "default", while compiling with "-define:mymod.test1=dlang -define:mymod.test2=dlang2" will return "dlang" and "dlang2"
Thank you for taking the time to do this. I am aware this is a common feature of other languages, and deliberately did not include it with D. The rationale is the same as why D does not allow version expressions, e.g. things like There are, however, workarounds as you have noted. These deliberately make things more difficult, as they should not be the first tool one turns to. One example used by the D compiler itself is the
and then is used with the line:
Personally, I would have preferred a file named
and then it could be simply imported with Nevertheless, this works and serves the compiler's need. To sum up, the lack of this feature being on the command line is deliberate, and intended to make the number of binaries that can be built a closed set. I appreciate the hard work you put into making this PR, but am sadly compelled to say no to it. |
It's true, #define often causes confusion in C
In fact my implementation doesn't introduce the problems of C #defines which mainly were:
My implementation actually currently looks more like Nim than C
Would a PR that allows auto-generating config.d be accepted? The ability to define configurations/constants without external tools is very useful, config.d is fine but by itself it doesn't cover the main use case i.e. allowing build system to define constants
In fact, if users need this feature, it's better to provide them with a well-made solution than a workaround like import(file). I literally have my own project in production full of import(files), it's disgusting to look at and difficult to manage. I'm considering whether to auto-generate a config.d somehow or keep an internal fork of D with this PR...
Fine, but what is the alternative? a config.d alone is not enough and simply ignoring the need I think is also wrong In any case, thanks for the review, I enjoyed doing this PR and I hope I can do something else that will eventually be accepted :-) |
Short of supporting this in the language with a trait, a configuration file using a fixed name that any build manager/compiler wrapper may employ with enum's (so it doesn't have anything to compile and can be freely overridden) would be the best solution. So rdmd and dub would be candidates for emitting this file. Dub should do that per-binary (not per package) and allow dependers to override vars that dependencies set. It should also be able to execute programs to get the value to set. I was going to eventually refactor |
This will introduce a solution similar in concept to the preprocessor macros commonly used in C/C++, but adapted to D which has no preprocessor.
In particular, allowing you to define a compile time constants by passing them to the compiler as a parameter.
Since that D doesn't have a preprocessor, I think the most elegant way to introduce a "global" constants, avoiding creating unwanted conflicts with code, is to introduce a traits capable of obtaining the constants defined via parameters passed to the compiler.
Currently some D-projects, including DMD itself, see
dmd/compiler/src/dmd/dinifile.d
Line 103 in 03ee26a
Example code:
Compiling with the parameters
-define:mymod.test1=dlang
will return the followingmessages
dlang
anddefault
, while compiling with-define:mymod.test1=dlang -define:mymod.test2=dlang2
will returndlang
anddlang2