everything that can be done with nim.cfg can be done with config.nims (after a number of issues were fixed in past few months), and config.nims is also much more featureful, so the question is:
should we deprecate nim.cfg in favor of config.nims format?
nim.cfg: how to have conditional flags to depend on compiler version? - Nim forum > I think it's impossible to do that in nim.cfg. Sorry.
and many others limitations
This should be largely automatable though
Ok. Deprecation of the old config system is tough as long as the new config system is so slow. :-(
but I'm not sure what he means by slow here; any pointer would be helpful; @araq?
https://github.com/nim-lang/Nim/issues/9405#issuecomment-431866723
"Personally, I'm all for deprecating nim.cfg. I've always felt that nims is the future and nim.cfg is the past since starting with Nim."
+1
Both are needed, because sometimes you have to use configuration that is not code.
is like using a config.py vs config.ini the code version might not be allowed everywhere, even more thinking of enterprise environments.
If nimble is the one definitive build tool for Nim, you are right. In some situations, people might prefer the more lightweight script-plus-compiler approach though, without the package manager part.
I am yet to run into a use case where I need to use full-blown Nim when I'm configuring Nim...
OP gives an example (how to have conditional flags to depend on compiler version), is it not valid anymore?
If I want to distribute just a binary, can/should I have one nimble file using nims for the complex build process and another for distribution?
Deprecation of the old config system is tough as long as the new config system is so slow. :-(
Anecdotally I have yet to experience any difference whatsoever. This may be due to the fact that I build using Nimble anyway, so the only point where I have to use config.nims/nim.cfg is to configure nimsuggest for editors - and in that case the cost of parsing the file is completely irrelevant
I am also in favor of using config.nims everywhere
As a NimScript noob, I like the power it apparently gives, but how would this emscripten config block
cc = clang
cpu = i386
clang.cpp.exe = "emcc"
clang.cpp.linkerexe = "emcc"
clang.options.always = "-s ASM_JS=1 --separate-asm"
clang.cpp.options.linker = "-Oz -s ASM_JS=1 --separate-asm"
from a nim.cfg look in nims? I guess
switch("clang.cpp.options.linker", "-Oz -s ASM_JS=1 --separate-asm")
and so on
Isn't the whole point of a configuration file that it remains declarative, in order to keep it simple for admins, non-programmers and programmers alike to grok? Ie that someone else does the work of providing the logic, and the person writing the config file only enters the data, in a format that's suitable for for entering data?
With an imperative style, you're no longer writing down what the configuration should be - instead, you're writing instructions for how to arrive at the desired configuration.
switch("clang.cpp.options.linker", "-Oz -s ASM_JS=1 --separate-asm") is certainly more difficult than clang.cpp.options.linker = "-Oz -s ASM_JS=1 --separate-asm", from a teaching perspective.
In fact, config.nims could more adequately be described as a plugin or scripting system than a configuration file - with all the implications that stem from that.
This way, option keys don't have to be strings, too. Why is there even a separate cfg parser, I thought DSLs like this is what meta-programming is for? :o)
speaking for myself here, but I don't think the (main) concern of the 'keep cfg' camp is that the syntax is different between --hint[LineTooLong]=off (cfg) and hint("LineTooLong", "on") (nims) as that's easy to switch to (and we can write a tool to automate if needed), their main concern is they want to be able to enforce a purely declarative config in some cases (eg enterprisey, whatever that means).
So I don't think we need to go out of our way to reverse engineer a type system that would give a meaning to what is originally a command line syntax hint[LineTooLong]=off, clang.cpp.options.linker etc. If anything, it'd be better to provide a helper macro or helper proc that parses these from a string, usable in config.nims:
config.nims:
parseFlags("""
--hint[LineTooLong]=off
--clang.cpp.options.linker
""")
that seems much less contrived.
Also your approach, while cute on the surface, faces real technical issues:
embedsrc()
which is ugly
ScriptMode:Declarative seems like a better way to satisfy the "keep cfg" camp.
ScriptMode:Declarative seems like a better way to satisfy the "keep cfg" camp.
Sorry, seems completely unrealistic to ever support this. If one doesn't like the config system, use the --skip*Cfg command line options and use a custom script that sets everything via command line.
I don't think the (main) concern of the 'keep cfg' camp is that the syntax is different between --hint[LineTooLong]=off (cfg) ...
That was not my proposal, the -- prefix is not required in cfg syntax.
So I don't think we need to go out of our way to reverse engineer a type system that would give a meaning to what is originally a command line syntax hint[LineTooLong]=off, clang.cpp.options.linker etc.
IMHO making things checkable by the compiler is worth the effort most of the time, but that's just an opinion. Btw., many (all?) hints, warnings and errors already have enums defined for them.
If anything, it'd be better to provide a helper macro or helper proc that parses these from a string, usable in config.nims
Yes, it could be done with a macro. Much nicer than string parsing:
cfg:
hint[LineTooLong]=off
clang.cpp.options.linker="-Oz -s ASM_JS=1 --separate-asm"
Again, without the --. The double dashes are less typing in a nims script than switch, but they have disadvantages: they introduce a UNIX/GNU specific convention into the config syntax of a multi-platform language and they work for config options which aren't even command line arguments.
--foo.bar syntax is un-constrained (see https://github.com/nim-lang/Nim/pull/8757#issuecomment-417781883) so it's impossible to map a type hierarchy to it.
Looks like a good point (without understanding the details). So it would be major changes to the config system or something like the config block above, I guess. Also solves your second point.
also not sure about how you'd map this: define:SYMBOL:VAL
It can be parsed (says dumpTree), so there's no problem if define is a macro.
I'd think most will agree that vscode is a sufficiently advanced project to serve as example.
It keeps the two concerns apart - configuration is configuration and extension is extension.
This allows it to offer excellent configuration features in a declarative way and enjoy all the benefits that a declarative style brings - there's an editor that knows all the possible config options, you get completion support for the values, there's a finite and well-defined set of things you can do which makes it easy to understand etc etc. It's just nice, and you need neither documentation, manuals or special knowledge to get going.
For the special cases that you need something more, you have an extension / plugin model. The plugin contains the logic of the configuration, and the configuration contains.. well.. the configuration. Doing it this way allows you to focus on creating a nice extension api without having to consider the constraints of what a nice config file/syntax would look like. This is where scripts and the like shine.
Both the config camp and the extension camp benefit.
The key here is that you have to separate systems that each are more simple and well defined, instead of spaghetti:ing everything into the same bowl. Both declarative and imperative styles have advantages and disadvantages - their relative usefulness is contextual to the specific problem.
There's nothing corporate about this, just plain common software engineering sense. You'll find it in the pragmatic programmer from years ago, and it still holds true today.
Configuration is just to provide the variables needed. Logical part should be handled on how our code works based on that variables
As long I don't have to code the configuration, whether nimscript of nim.cfg would be fine. It's configuration after all.
The TS's initial problem is that he couldn't access Nim compiler version to compile his codes accordingly. Means, it's not configuration problem, it should be another problem altogether that he needed to code a program that would compile his codes.