How to echo/print at compile time in Nim? - compile-time

When working on compile time features it would be nice to echo something at compile time. If an echo is withing a macro it is already executed at compile time. But is it also possible to print something at compile time e.g. from the global scope? I'm looking for a function like echoStatic in this:
echoStatic "Compiling 1. set of macros..."
# some macro definitions
echoStatic "Compiling 2. set of macros..."
# more macro definitions

There is no need for a special echoStatic. This is solved by the general solution of running code at compile time, which is to use a static block:
static:
echo "Compiling 1. set of macros..."
# some macro definitions
static:
echo "Compiling 2. set of macros..."
# more macro definitions

In languages like C, C++ and D, you can typically use a pragma for this job. This also works for Nim:
from strformat import `&`
const x = 3
{. hint: &"{$typeof(x)} x = {x}" .} # <file location> Hint: int x = 3
It also prints the file, the line and the column which can be useful for compile-time debugging.

Related

How to issue Message Before Build--or seq problems

I'm trying to add helpful messages for arbitrary builds. If the build fails the user can, for example, install the package with different arguments.
My interface idea is to provide a function, build-with-message, that would be called with something like this:
build-with-message
''Building ${pkg.name}. Alternative invocations are: ..''
pkg
My implementation is based on builtins.seq
build-with-message = msg : pkg :
seq
(self.runCommand "issue-message" {} ''mkdir $out; echo ${msg}'')
pkg;
When I build a package with build-with-message I never see the message. My hunch is that seq evaluates the runCommand far enough to see that a set is returned and moves on to building the package. I tried with deepSeq as well, but a deepSeq build fails on runCommand. I also tried calling out some attributes from the runCommand, e.g.
(self.runCommand "issue-message" {} ''mkdir $out; echo ${msg}'').drvPath
(self.runCommand "issue-message" {} ''mkdir $out; echo ${msg}'').out
My thought being that calling for one of these would prompt the rest of the build. Perhaps I'm not calling the right attribute, but in any case the ones I've tried don't work.
So:
Is there a way to force the runCommand to build in the above scenario?
Is there already some builtin that just lets me issue messages on top of arbitrary builds?
Here's me answering my own question again, consider this a warning.
Solution:
I've in-lined some numbered comments to help with the explanation.
build-with-message = msg : pkg :
let runMsg /*1*/ = self.runCommand "issue-message"
{ version = toString currentTime; /*2*/ } ''
cat <<EOF
${msg}
EOF
echo 0 > $out /*3*/
'';
in seq (import runMsg /*4*/) pkg; /*5*/
Explanation:
runMsg is the derivation that issues the message.
Adding a version based on the current time ensures that the build of runMsg will not be in /nix/store. Otherwise, each unique message will only be issued for the first build.
After the message is printed, a 0 is saved to file as the output of the derivation.
The import loads runMsg--a derivation, and therefore serialized as the path $out. Import expects a nix expression, which in this case is just the number 0 (a valid nix expression).
Now, since the runMsg output will not be available until after it has been built, the seq command will build it (issuing the message) and then build pkg.
Discussion:
I take note of Robert Hensing's comment to my question--this may not be something Nix was not intended for. I'm not arguing against that. Moving on.
Notice that issuing a message like so will add a file to your nix store for every message issued. I don't know if the message build will be garbage collected while pkg is still installed, so there's the possibility of polluting the nix store if such a pattern is overused.
I also think it's really interesting that the result of the runMsg build was to install a nix expression. I suppose this opens the door to doing useful things.

Flex dropping predefined macro

I have the following flex source:
%{
#if !defined(__linux__) && !defined(__unix__)
/* Maybe on windows */
#endif
int num_chars = 0;
%}
%%
. ++num_chars;
%%
int main()
{
yylex();
printf("%d chars\n", num_chars);
return 0;
}
int yywrap()
{
return 1;
}
I generate a C file by the command flex flextest.l and compile the result with gcc -o fltest lex.yy.c
To my surprise, I get the following output:
flextest.l:2:37: error: operator "defined" requires an identifier
#if !defined(__linux__) && !defined(__unix__)
After further checking, the issue seems to be that flex has actually replaced __unix__ with the empty string, as shown by:
$ grep __linux_ lex.yy.c
#if !defined(__linux__) && !defined()
Why does this happen, and is it possible to avoid it?
It's actually m4 (the macro processor which is used by current versions of flex) which is expanding __unix__ to the empty string. The Gnu implementation of m4 defines certain symbols to empty macros so that they can be tested with ifdef.
Of course, it's (better said, it was) a bug in flex. Flex shouldn't allow m4 to expand macros within user content copied from the scanner definition file, and the current version of flex correctly arranges for the text included from the scanner description file to be quoted so that it will pass through m4 unmodified even if it happens to include a string which could be interpreted by m4 as a macro expansion.
The bug is certainly present in v2.5.39 and v2.6.1 of flex. I didn't test all previous versions, but I suppose it was introduced when flex was modified to use m4, which was v2.5.30 according to the NEWS file.
This particular quoting issue was fixed in v2.6.2 but the current version of flex (2.6.4) contains various other bug fixes, so I'd recommend you upgrade to the latest version.
If you really need a version which could work with both the buggy and the more recent versions of flex, you could use one of the two following hacks:
Find some other way to write __unix__. One possibility is the following
#define C(x,y) x##y
#define UNIX_ C(__un,ix__)
#if !defined(__linux__) && !UNIX_
That hack won't work with defined, since defined(UNIX_) tests whether UNIX_ is defined, not whether what it expands to is defined. But normally built-in symbols like __unix__ are actually defined to be 1, if they are defined, and the #if directive treats any identifier which is not #define'd as though it were 0, which means that you can usually leave use x instead of defined(x). (However, it will produce different results if there were a #define x 0 in effect, so it's not quite a perfect substitute.)
Flex, like many m4 applications, redefines m4's quote marks to be [[ and ]]. Both the buggy flex and the corrected versions substitute these quote marks with a rather elaborate sequence which effectively quotes the quote marks. However, the buggy version does not otherwise quote user-defined text, so macro substitutions will be performed in user text. (As mentioned, this is why __unix__ becomes the empty string.
In flex versions in which user-defined text is not quoted, it is possible to invoke the m4 macro which redefines quote marks. These new quote marks can then be used to quote the #if line, preventing macro substitution of __unix__. However, the quote definition must be restored, or it will completely wreck macro processing of the rest of the file. That's a bit tricky because it is impossible to write [[. (Flex will substitute it with a different string.)
The following seems to do the trick. Note that the macro invocations are placed inside C comments. The changequote macros will expand to an empty string, if they are expanded. But in flex versions since v2.6.2, user-supplied text is quoted, so the changequote macros will not be expanded. Putting them inside comments hides them from the C compiler.
%{
/*m4_changequote(<<,>>)<<*/
#if !defined(__linux__) && !defined(__unix__)
/*>>m4_changequote(<<[>><<[>>,<<]>><<]>>)*/
/* Maybe on windows */
#endif
(The m4 macro which changes quote marks is changequote but flex invokes m4 with the -P flag which changes builtins like changequote to m4_changequote. In the second call to changequote, the two [ which make up the [[ sign are individually quoted with the temporary << quote marks, which hides them from the code in flex which modifies use of [[.)
I don't know how reliable this hack is but it worked on the versions of flex which I had kicking around on my machine, including 2.5.4 (pre-M4) 2.5.39 (buggy), 2.6.1 (buggy), 2.6.2 (somewhat debugged) and 2.6.4 (more debugged).

Get list of #defines as Token or string in Premake 5

I am using a custom build command to run the nasm assembler on a .asm file in my C++ project. I am using %idefs in the assembler code to only compile the code I need. I am checking for the same #defines as in the C++-Code and use define() in Premake 5 to set those, but additionally I need to pass them to nasm on its command line invocation in my Custom Build Command. What I am looking for is a way to concatenate or string replace the Premake internal list of #defines into the command line invocation string of the buildcommands() call. Is there a Premake Token or a way to introspect the lua variables and generate a list from that?
Note that my command line invocation specifically is
buildcommands "nasm.exe -f win32 -o %{cfg.objdir}%{file.basename}.lib %{file.abspath} -DNDEBUG"
Suppose I set defines { "FEAT_A", "FEAT_B" } in my premake5.lua. I then would like to to add -DFEAT_A -DFEAT_B automatically to that build command similar to the -DNDEBUG so I cannot simply insert a simple token. I guess I do have to do something like this (lua pseudo code as I don't really know the syntax):
define_flags = wks.defines.join(" -D")
buildcoommands("nasm.exe [...]"..define_flags)
Do you know if something like this is possible?
How about something like this?
buildcommands('nasm.exe [...] %{table.implode(cfg.defines, "-D", "", " ")} [...]')

Luac don't work with one script

I have embedded lua and I want precompile my script. For that, I call the main of luac (with argc the number of file is 1). My problem is on the function doargs of luac. I don't understand the use of the variable i. Because when I use one script. The result of i after the doargs function is 1. And in the main function we have argc -= i after. And so argc = 0 and I have a error "no file". Any idea ?
luac is meant to be a command line utility for compiling .lua files. This expected usage is the reason why you're getting an error.
When you start an executable the OS passes the name of the program as its first argument (argv[0]). The luac main function assumes it is being called by the OS, so it expects that there will always be at least one argument and its argv[0] will be the name of the executable.
For this reason doargs starts its for loop at 1 and will always ignore that first (0th) argument. It returns how many options it has processed, which is also the offset of the first filename in the argv array. The main function uses this to know where the list of files starts.
If you really want to use the main function to precompile your scripts, then supply an extra dummy argument at the beginning of your argument array and list your files after that. Preferably you should use luac from the command line and supply an output file where the precompiled script will be stored like this:
luac -o outputFile script.lua
Alternatively, take a look at chapter 8 of Programming in Lua (Compilation, Execution, and Errors) for a pure Lua solution, or the the luaL_dofile, luaL_dostring, lua_dump, and lua_load functions in the Reference Manual for a C API solution.

DART string constant set to timestamp as at compilation

How can I get a string constant automatically set to the datestamp as at compile time?
Something like:
const String COMPILE_DATESTAMP = eval_static(DateTime.now().toString());
...
String s = "This program was compiled $COMPILE_DATESTAMP";
where s would then be for e.g.
"This program was compiled 1971-02-03 04:05:06"
Thanks for the question!
There's no required compile step in Dart. (We do have an optional Dart-to-JavaScript compiler, or even a Dart-to-Dart processor that does tree shaking.) Dart's VM accepts input as text files. Similar to Ruby or Python, it runs text-based scripts.
As others have mentioned, this is a job for some sort of build step.
I'm new to Dart, but I haven't seen anything in the documentation to suggest that such a thing is possible. I strongly suspect that it isn't.
If you really need functionality like you describe, I think your best bet is to roll your own build script. Something simple like:
#!/bin/bash
sed -ri "s/INSERT_DATETIME_HERE/`date`/" $1
dart2js $1 -o$1.js
could be modified to suit your needs. (I'd want some sanity checks in there if it were me; I'm just suggesting a starting point.) Your code would become:
const String COMPILE_DATESTAMP = "INSERT_DATETIME_HERE";
...
String s = "This program was compiled $COMPILE_DATESTAMP";
You must write another dart program that could examine the actual compiled program. Then is simple as:
File compiledApp = new File('path/to/compiled/app.dart');
compiledApp.lastModified().then(
(modifiedDate)
{
print("This program was compiled $modifiedDate");
},
onError: (exp)
{
// File doesn't exist ?
}
);
This trick build on knowledge that compiler will modify the 'last modify date' of the file

Resources