nim-lang / nimble

Package manager for the Nim programming language.
https://nim-lang.github.io/nimble/index.html
Other
1.25k stars 191 forks source link

No way to populate source code with a package information at compile-time #625

Closed samdmarshall closed 5 years ago

samdmarshall commented 5 years ago

Maybe i'm missing something incredibly obvious here but I am struggling with what seems to be a trivial problem of wanting my package's source code to contain the same value as that of the .nimble file. I have found a couple of my personal packages wildly out of sync because I end up modifying the code and forgetting to update the .nimble file as well. I see that in the nimble.nimble file that you are pulling the const from one of the source files, but it feels a bit backwards and awkward to have to insert that into every nimble file and arrange code in such a way; vs. having these values be provided as compile-time constants following a particular naming convention or pattern that can be consumed in the source file.

dom96 commented 5 years ago

AFAIK other languages don't solve this at all, they just required you to duplicate the version (exceptions might be Python and other interpreted langs but IMO doesn't count)

samdmarshall commented 5 years ago

again, maybe i'm missing something super obvious here but it seems like if nimble's exec of the compilation command was to add either environment variables or pass defines to the compiler with the prefix of NIMBLE_PACKAGE_/NimblePackage for properties of name, version, etc. that it would be a simple and very useful integration.

dom96 commented 5 years ago

That's a great idea and I don't see why it can't work out. That would certainly cut one reason for this Nimscript integration in Nimble... No idea why we didn't do this in the first place. Maybe I'm too tired to remember, @Araq?

Araq commented 5 years ago

I don't understand the problem with include "package.nimble" to get at the version information.

samdmarshall commented 5 years ago

oh; you are right; id not considered that option. it feels like that should be a more documented common way to setup a package. i’ll poke around with this and make a PR suggesting that as the preferred method in the docs if that’s okay with both of you.

samdmarshall commented 5 years ago

Okay, I've figured this out and now have the following snippet:

# Importing nimscript is necessary to get the package-related variables
#   defined by the `.nimble` file.
import system/nimscript

# Use `include` here because the contents need to be inserted into this file, 
#   rather than imported as a module (as that would cause a name conflict 
#    with the binary's main module).
include "../fetch.nimble"

# Use `var`, otherwise these will be treated as compile-time constants, instead 
#   of being evaluated at run-time (to get whatever the `.nimble` file contains).
var
  # Give the package meta-data variables proper names to be used internally 
  #   to conform to naming conventions.
  AppName*        = packageName
  AppVersion*     = version
  AppAuthor*      = author
  AppDescription* = description
  AppLicense*     = license

presumably this could be cleaned up into a macro or something that would result in a 1-liner or get it done automatically so that there isn't a knowledge/familiarity requirement in using this trick.

dom96 commented 5 years ago

Honestly, I still prefer your idea to pass this to nim via --define:NimbleVersion="0.1.0" or something. It makes far more sense to keep the version inside the Nimble file.

We can even make a module called versioninfo:

proc getNimbleVersion(): Option[string] =
  when defined(NimbleVersion): return some(NimbleVersion)
  else: return none[string]()

or something like that to make sure it works without Nimble.

samdmarshall commented 5 years ago

yeah i agree; i’ve run into some minor issues with this (ambiguity with symbols from the nimscript module vs the system/os/etc modules). personally i’d like to have access to:

this seems to be in a similar vein as the hostOs/hostCpu/compileDate/compileTime values that are already provided by the system; maybe move those with these into a buildinfo module or something that does all the handling of these values then makes them visible exports?

tbh one of my initial work-around ideas was to write a nimscript that would generate a new bin file to include at build which just had const values of the serialized variables (like config.h with autoconf in C), but it felt a bit like re-inventing a wheel, and made this issue instead.

zah commented 5 years ago

I usually do this the other way around. I create a small and simple version module with constants that gets included/imported in the the project nimble file.

FedericoCeratto commented 5 years ago

Is there a way in Nimble to extract such data, including the list of dependencies, and print it out in a parsable format?

dom96 commented 5 years ago

Is there a way in Nimble to extract such data, including the list of dependencies, and print it out in a parsable format?

nimble dump? is that what you mean?

FedericoCeratto commented 5 years ago

@dom96 thanks. Any way to extract a more structured/parsable output than requires: "nim >= 0.15.0, regex >= 0.7.4" ?

dom96 commented 5 years ago

@FedericoCeratto If you want to parse this you should use Nimble as a library.

samdmarshall commented 5 years ago

this is starting to become off-topic but it seems like that command is wanting a --json flag for machine-readable output.

dom96 commented 5 years ago

Since passing --define:NimbleVersion="0.1.0" has very little chance of breaking anything I'm just going to make Nimble do it for 0.11.0.

dom96 commented 5 years ago

So now we have an alternative of how to share the version number, the only downside is if your program is compiled using Nim then you won't get the version number. To see how to use this checkout the associated commit.