post-build event with multiple if/copy combinations only execute if first file does not exist - delphi

Given the bin\ directory inside the Delphi project contains the files Cert.pem and Key.pem, the below Delphi post-build event only copies both files if C:\Binaries\Cert.pem does not exist:
if not exist $(OUTPUTDIR)Cert.pem (copy bin\Cert.pem $(OUTPUTDIR))
if not exist $(OUTPUTDIR)Key.pem (copy bin\Key.pem $(OUTPUTDIR))
As soon as C:\Binaries\Cert.pem exists, the Key.pem file is never copied.
How can I solve this in the post-build event?
Edit: unlike my 2014 post, this is indeed possible using parentheses. See my answer below.

The problem with Delphi post-build events is that they are not batch files.
It means that statements that look like lines are being concatenated by the Delphi IDE into one big & ampersand separated statement. This ensures the commands are executed in sequence, as per Command Redirection, Pipes - Windows CMD - SS64.com:
commandA & commandB Run commandA and then run commandB
So this is the actual statement that gets executed:
if not exist $(OUTPUTDIR)Cert.pem (copy bin\Cert.pem $(OUTPUTDIR))&if not exist $(OUTPUTDIR)Key.pem (copy bin\Key.pem $(OUTPUTDIR))
The problem here is that now the second if is seen as a continuation of the "then" part of the first if statement: the second if never executes when the $(OUTPUTDIR)Cert.pem exists.
What helps is a little known feature that you can wrap each command inside parentheses. Normally this is to allow one command to span multiple lines (especially for if, and for..do loops), but it also works on one line.
Wrapping each line having an if statement inside parentheses ensures they become standalone statements not affecting the other lines, even if they are being concatenated with & ampersand separators.
In the dialog it looks like this:
(if not exist $(OUTPUTDIR)Cert.pem (copy bin\Cert.pem $(OUTPUTDIR)))
(if not exist $(OUTPUTDIR)Key.pem (copy bin\Key.pem $(OUTPUTDIR)))
That way, the IDE translates it into one statement:
(if not exist $(OUTPUTDIR)Cert.pem (copy bin\Cert.pem $(OUTPUTDIR)))&(if not exist $(OUTPUTDIR)Key.pem (copy bin\Key.pem $(OUTPUTDIR)))
Now it works as intended:
When $(OUTPUTDIR)Cert.pem exists but $(OUTPUTDIR)Key.pem does not, only $(OUTPUTDIR)Cert.pem is copied
When $(OUTPUTDIR)Cert.pem does exists but $(OUTPUTDIR)Key.pem does, only $(OUTPUTDIR)Key.pem is copied
when neither exist, both are copied
when both exist, neither are copied
I did not know this "trick" when writing my 2014 post Delphi prebuild/prelink/postbuild events, so I need to write an update for it.
Searching for batch file parentheses site:microsoft.com -site:social.technet.microsoft.com -site:answers.microsoft.com did not reveal it in the official documentation, but I am not surprised as it grew hysterically, instead of being designed. Or like the Old New Thing attributes h2g2:
Much like the universe, if anyone ever does fully come to understand Batch then the language will instantly be replaced by an infinitely weirder and more complex version of itself. This has obviously happened at least once before ;)
The best documentation I could find was at Parenthesis/Brackets - Windows CMD - SS64.com:
Parenthesis can be used to split commands across multiple lines. This can make code more readable. Variables will be evaluated for the code block just as if the command was a single line.
(command)
(
command
command )
Things that break inside parenthesis
The CMD shell does not use any great intelligence when evaluating parenthesis, so for example the command below will fail:
IF EXIST MyFile.txt (ECHO Some(more)Potatoes)
...

Use multiple build events instead of putting both commands in the same event.
Executing the source lines of a build event.
I can cut this short very easily: build events are not batch files.
What happens is that all lines in your build event are concatenated together using ampersand (&) signs which are used to execute multiple commands on one command line.
This means that all the fancy control structures (if statements, setlocal, for loops) are not possible inside build events.
ref: Pasted from a blog post: Delphi prebuild/prelink/postbuild events written by Jeroen W. Pluimers
Makes me wonder why you asked since it looks like you wrote the answer in 2014. :)

Related

Multiline command-line editing in Gforth console

I have just started learning the Forth programming language.
I'm using Gforth on Ubuntu. In Gforth interactive console, I want to do indentation but it requires changing line. Enter key didn't work, it executed code. For comparison, for example, when one tests JavaScript code in web browser console, shift+enter change line without executing code. I want something like that. What key should I press? Is there a way other than using text editors like vim?
Best.
Gforth doesn't support multiline editing (see the manual).
A workaround is to edit a file in your favorite editor in another window and reload this file in Gforth console as:
include /tmp/scratch.fs
An external file can be also edited in Gforth console via a command like:
"vim /tmp/scratch.fs" system
So a one-liner for that is:
"vim /tmp/scratch.fs" system "/tmp/scratch.fs" included
That can be wrapped into a definition as:
: scratch "vim /tmp/scratch.fs" system "/tmp/scratch.fs" included ;
So the word scratch will open an editor and than load the edited file.
NB: if you use a quite old build of Gforth, you have to use s" ccc" instead of "ccc" for string literals.
To conditionally include/exclude some parts in a file the words [defined] and [if] can be used; to erase the previous instance of the loaded definitions the word marker can be used as:
[defined] _clear [if] _clear [then]
marker _clear
\ some definitions
\ ...
Take into account that usual control-flow words can be used in definitions only.

Isabelle's document preparation

I would like to obtain the LaTeX code associated with this theory. Previous answers only provide links to the documentation. Let me describe what I did.
I went to the directory of Hales.thy and executed isabelle mkroot, followed by isabelle build -D ., which generated a file named document and a *.pdf file which was suspiciously (nearly) empty. Modifications of this command by adding Hales.thy as a parameter didn't succeed.
I would appreciate if someone could describe briefly the commands needed.
As a precaution, copy the file Hales.thy into a new directory that does not contain any other files and run isabelle mkroot again.
If I understand correctly, your theory contains sorry. In this case, for the build to succeed you need to enable the quick_and_dirty mode. For this, before the first occurrence of sorry in your theory file, you need to insert declare [[quick_and_dirty=true]].
Your theory contains raw text that is not suitably formatted. Try replacing the relevant lines with the following: text‹The case \<^text>‹t^2 = 1› corresponds to a product of intersecting lines which cannot be a group› and text‹The case \<^text>‹t = 0› corresponds to a circle which has been treated before›.
Once this is done, you should be able to use the ROOT file in the appendix below. As you can see, I have specified the theory file explicitly and also added the relevant imported sessions.
Appendix
session Hales = HOL +
options [document = pdf, document_output = "output"]
sessions
"HOL-Library"
"HOL-Algebra"
theories
"Hales"
document_files
"root.tex"

How can I get the output of ls

How can I get the output of ls? I want to add a indirection operator =>, and it's function is same as >, it means in the command line $ls => Files, the list of files in the directory is stored in the file Files
Output redirection (and all other redirection for that matter) is a facility provided by the shell, not by the ls program. The ls just writes its output to standard output and, if the shell has redirected that to a file, that's where it goes.
So, if you want to add a => token, it's the shell that you're going to have to modify, recompile and install. That's not necessarily an easy task, I've made changes to bash in the past and, while it's relatively easy to tinker around the edges (I added an internal command for outputting the PS1 result string), I suspect redirection may be a little more difficult.
Still, it may be a matter of simply creating a new token => and copying the code that's currently executed for >. It may also be that ash, the Minix3 shell, is a lot cleaner than bash. My advice would be to investigate ash, specifically the version found in Minix3, and just have a play.

Path definition in makefile

I have a doubt about indicating a path in makefile and I'd like to have a clarification.
Suppose my structure is made this way:
/home/machinename/softwarefolder/mainfolder
--------------------------------------------> /subfolder1
--------------------------------------------> /subfolder2
This means that both subfolder1 and subfolder2 are at the same nesting level in /mainfolder.
Now I'm compiling something inside subfolder 2 (this means that I cd to that folder) that uses a configure file with a macro pointing to a path that, in my case, it's in subfolder1.
This configure file used by the program in subfolder2 to compile is generated automatically by the program itself after running ./configure
The automatically generated configure file has the macro defined this way
MACRO = ../subfolder1
Do the two dots (..) indicate, as in the cd command, "go back one step" (and, therefor, the configure file is pointing to the right folder)?
If the answer to the first question is "no", then why substituting the aforementioned macro with
MACRO = /home/machinename/softwarefolder/mainfolder/subfolder1
generates a "missing separator" error in compile-time?
Sorry for the probably trivial question and thanks for the help!
Make doesn't interpret the content of variables in any way, for the most part. The question of how the .. will be interpreted depends entirely on where the variable is used. If it's used in a place where a path like ../subfolder1 makes sense, then that's how it will be interpreted. If not, not.
Since you don't show how $(MACRO) is used, we can't help. But in general the answer to your question is "yes, it means go up to the parent directory".
As for your second question, there is no way I can envision that changing just that one line will result in a "missing separator" error. Maybe your editor "helpfully" made other changes to the file such as removing TABs and substituting spaces, or adding TABs? TAB characters are special in makefiles.
If you want help with the second question you must provide (a) the exact error you received (cut and paste is best), and (b) the exact text of the rule in the makefile at the line number specified in the error message.

How Can I Handle Parameters With Spaces in Delphi?

My program accepts input file names either as command line parameters or in a drag and drop operation or in Explorer by clicking on filenames with an extension that is associated with my program.
The command line and drag and drop work fine, but it is clicking on the filenames in Explorer that causes problems when the filepaths of the files clicked on have spaces in them, e.g.:
c:\temp\file one.txt
c:\my directory\filetwo.txt
c:\my directory\file three.txt
then, the ParamStr function gives me back:
ParamStr(1): c:\temp\file
ParamStr(2): one.txt
ParamStr(3): c:\my
ParamStr(4): directory\filetwo.txt
ParamStr(5): c:\my
ParamStr(6): directory\file
ParamStr(7): three.txt
How can I best reconstitute these back into the three filenames that I need?
It might be your shell file association that does not include the pair of "".
Like these ones for opening:
"C:\Program Files\WinRAR\WinRAR.exe" "%1"
or with DDE message:
[open("%1")]
Command-line parameters with spaces in them, such as filenames, should be quoted. This makes the param parser realize that it's supposed to keep them together. If the user's not quoting the filename, it's operator error.
If a drag-and-drop system is doing this, on the other hand, then you've got a bug in your drag-and-drop library and you need to talk to whoever created it. I'm a bit confused, though, as to why drag-and-drop operations are messing with ParamStr. That should only be set by the params passed to your program at the moment it's invoked, not once it's up and running. Maybe I'm missing something?
i use the CmdLineHelper unit, from here.

Resources