Extracting directory / file names in a Makefile - c#

Could someone help me understand the behaviour of the makefile, below? To give some context, I am trying to generated a series of c# classes from a set of .proto files. The proto files are contained within a directory structure which i want to mirror in the output. So, assuming my source files are in a folder called 'Source' and I am outputting into a folder called 'Generated', if a file resides in:
'Source/Foo/Bar/myfile.protoc'
then output should be:
'Generated/Foo/Bar/MyFile.cs'.
This seems simple enough however I am seeing some strange behaviour when using dir/notdir in the make file. here is an example:
# Makefile to build message definitions within this repo
PROTOS:= SourceFiles/Module_1/BasicMessage.proto SourceFiles/Module_2/BasicMessage.proto
withVariables:
for proto in $(PROTOS) ; do \
echo $(dir $$proto) ; \
echo $(notdir $$proto) ; \
done;
hardCoded:
echo $(dir ./SourceFiles/Module_1/BasicMessage.proto)
echo $(notdir ./SourceFiles/Module_1/BasicMessage.proto)
echo $(dir ./SourceFiles/Module_2/BasicMessage.proto)
echo $(notdir ./SourceFiles/Module_2/BasicMessage.proto)
Essentially, when I have the collection of file names in a variable and try to iterate them, dir/notdir does not seem to recognised the separators in the path. Running Make hardCoded here gives:
./SourceFiles/Module_1/
BasicMessage.proto
./SourceFiles/Module_2/
BasicMessage.proto
which is what i would expect. However, running withVariables gives:
./
SourceFiles/Module_1/BasicMessage.proto
./
SourceFiles/Module_2/BasicMessage.proto
I am still pretty new to make files, so I am probably missing something simple, but if anyone can explain why these two examples behave differently, it would be greatly appreciated.

The recipes are expanded by make before being passed to the shell. So, in the recipe of withVariables, the $(dir $$proto) and $(notdir $$proto) are expanded to ./ and $proto, respectively. The recipe becomes:
for proto in SourceFiles/Module_1/BasicMessage.proto SourceFiles/Module_2/BasicMessage.proto; do \
echo ./ ; \
echo $proto ; \
done;
which logically produces the output you see. You cannot use make functions in your recipes and expect them to be executed by the shell. Instead you can invoke the standard dirname and basename external programs from your recipe:
withVariables:
for proto in $(PROTOS); do \
echo $$(dirname $$proto); \
echo $$(basename $$proto); \
done
The recipe is expanded by make as:
for proto in SourceFiles/Module_1/BasicMessage.proto SourceFiles/Module_2/BasicMessage.proto; do \
echo $(dirname $proto); \
echo $(basename $proto); \
done
which, when executed by the shell, outputs:
host> make withVariables
SourceFiles/Module_1
BasicMessage.proto
SourceFiles/Module_2
BasicMessage.proto

Related

Xmlstarlet ed encoding and powershell inside Process C#

I want to use xmlstarlet from the powershell started with Process in a C# application.
My main problem is that when I use this code:
./xml.exe ed -N ns=http://www.w3.org/2006/04/ttaf1 -d '//ns:div[not(contains(#xml:lang,''Italian''))]' "C:\Users\1H144708H\Downloads\a.mul.ttml" > "C:\Users\1H144708H\Downloads\a.mul.ttml.conv"
on powershell I get a file with the wrong encoding (I need UTF-8).
On Bash I used to just
export LANG=it_IT.UTF-8 &&
before xmlstarlet but on powershell I really don't know how to do it.
Maybe there is an alternative, I saw that xmlstarlet is able to use sel --encoding utf-8 but I don't know how to use it in ed mode (I tried to use it after xml.exe after ed etc... but it always fail).
What is the alternative to export LANG=it_IT.UTF-8 or how to use --encoding utf-8?
PS. I tried many and many things like:
$MyFile = Get-Content "C:\Users\1H144708H\Downloads\a.mul.ttml"; $Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding $False; [System.IO.File]::WriteAllLines("C:\Users\1H144708H\Downloads\a.mul.ttml.conv", $MyFile, $Utf8NoBomEncoding)
And:
./xml.exe ed -N ns=http://www.w3.org/2006/04/ttaf1 -d '//ns:div[not(contains(#xml:lang,''Italian''))]' "C:\Users\1H144708H\Downloads\a.mul.ttml" | Out-File "C:\Users\1H144708H\Downloads\a.mul.ttml.conv" -Encoding utf8
But characters like è à ì ù are still wrong. If I try to save the original file with Notepad before the conversion it works (only if I don't use xmlstarlet)... but I need to do the same thing in powershell and I don't know how.
EDIT.
I was able to print my utf8 on powershell:
Get-Content -Path "C:\Users\1H144708H\Downloads\a.mul.ttml" -Encoding UTF8
But I'm still not able to do the same thing with xmlstarlet.
In the end I decided to create a native C# method and I just used a StreamReader to ReadLine by line the file. With a simple Contains I decide where is the xml:lang="Language" and I then start to add every line to a string. Of course I added the head and the end of my file before the while loop and I stop to add every line when I read a line that Contains . I know that this is not the best way to do things, but it works for my case.

redirecting output from an external dll in powershell

I have a C# assembly that processes an xml file and at the end spits out the results to the console.
e.g. Console.WriteLine(_header.ToString());
I can load this dll in powershell and call the right method like this:
[sqlproj_doctor.sqlprojDoctor]::ProcessXML($file) | out-file ./test.xml
All is well.
The problem begins when I want to redirect the output. For some reason stdout is empty. What am I missing? I need to be further process the output of this dll.
Note: If I compile the same code as an executable, it correctly populates the standard output stream and I can redirect the output.
another note: as a workaround, I changed the method from void to string, and can now manipulate the returned string.
When you call [Console]::WriteLine('SomeText'), it write to PowerShell process stdout, not to command output, and so it can not be redirected from inside same PowerShell process, by standard PowerShell operators, like this:
[Console]::WriteLine('SomeText')|Out-File Test.txt
You have to spawn new PowerShell process, and redirect output of that new process:
powershell -Command "[Console]::WriteLine('SomeText')"|Out-File Test.txt
In case if some command use [Console]::WriteLine to write to console, you can capture that output without starting new PowerShell instance:
$OldConsoleOut=[Console]::Out
$StringWriter=New-Object IO.StringWriter
[Console]::SetOut($StringWriter)
[Console]::WriteLine('SomeText') # That command will not print on console.
[Console]::SetOut($OldConsoleOut)
$Results=$StringWriter.ToString()
$Results # That variable would contain "SomeText" text.
Although this does not help if command does not use [Console]::WriteLine, but write to stdout stream directly:
$OldConsoleOut=[Console]::Out
$StringWriter=New-Object IO.StringWriter
[Console]::SetOut($StringWriter)
$Stdout=[Console]::OpenStandardOutput()
$Bytes=[Console]::OutputEncoding.GetBytes("SomeText"+[Environment]::NewLine)
$Stdout.Write($Bytes,0,$Bytes.Length) # That command will print on console.
$Stdout.Close()
[Console]::SetOut($OldConsoleOut)
$Results=$StringWriter.ToString()
$Results # That variable will be empty.

Invoke-Expression, Verbatim Strings, and Invoking Scripts From Other Scripts in PS

I am attempting to call a ps1 script from another ps1 script. These scripts all exist in the same directory. I am able to get a string representing the current directory using the following:
$ScriptDir = Split-Path $MyInvocation.MyCommand.Path -Parent
This works, no problem. To call the secondary script, I am using the Invoke-Expression command, using the above $ScriptDir path and hardcoding the script name (this can be seen at the bottom of this post). However, every time I do this it does a path complaint similar to:
C:\Users\Administrator\Documents\Visual : The term 'C:\Users\Administrator\Documents\Visual' is not recognized as the name of a cmdlet, function, script file, or
operable program.
Normally, in C# this is no problem for me to solve, it is a verbatim string issue. However, I do not see a way to make this work in powershell. For reference, here is a slimmed down version of the completed code I am using to test:
ScriptDir = Split-Path $MyInvocation.MyCommand.Path -Parent
Write-Host "InvocationName:" $MyInvocation.InvocationName
Write-Host "Path:" $MyInvocation.MyCommand.Path
write-host "Starting Test..."
Invoke-Expression "$ScriptDir + \Foo.ps1"
I know I am missing something small.
Instead of
Invoke-Expression "$ScriptDir + \Foo.ps1"
It should be:
& "$ScriptDir\Foo.ps1"

Visual Studio 2012 Post Build Events - Error Code 255

Here is my attempt to copy my application executable to another folder changing it's name:
IF $(ConfigurationName) == Release (
SET DESTINATION=$(ProjectDir)Output\Distribution
IF NOT EXIST "%DESTINATION%" ( MD "%DESTINATION%" )
XCOPY /Q /Y "$(TargetPath)" "%DESTINATION%"
RENAME "%DESTINATION%\$(TargetFileName)" "$(TargetName).Plain$(TargetExt)"
)
I've tried everything to make it work, but it always throw error code 255 or 1, it depends. Running that code with a plain batch file works like a charm!
You need to enable delayed expansion, using the SETLOCAL EnableDelayedExpansion command. Do it at the top of the post-build event. After that, you can access your variable by using not %VARIABLE_NAME%, but !VARIABLE_NAME! (use an exclamation symbol on either side of the variable name, not the percentage symbol which you would use in a regular batch file).
So, for example
SETLOCAL EnableDelayedExpansion
IF $(ConfigurationName) == Release (
SET DESTINATION=$(ProjectDir)Output\Distribution
echo My destination dir is !DESTINATION!
)
This will output something like
My destination dir is D:\Work\Projects\PBExample\Output\Distribution.
Since the Post-build event command line actually runs as a batch file you need to escape characters like % by doubling them to %%:
https://stackoverflow.com/a/13552702/74585

How to run Doxygen Makefile?

I have created a .NET C# project that I have commented using blocks similar to ///<summary>A summary...</summary> that I would like to document using Doxygen. I have set up Doxygen and it runs generating a some 100 .tex-files and a Makefile.
As I have understood, the Makefile is the key to generating the documentation as a PDF, however I do not get it to work.
I'm using a Mac to do the LaTeX and Doxygen bit by writing make -f Makefile in the Terminal when I am in the Doxygen LaTeX output directory.
all: refman.pdf
pdf: refman.pdf
refman.pdf: clean refman.tex
pdflatex refman
makeindex refman.idx
pdflatex refman
latex_count=5 ; \
while egrep -s 'Rerun (LaTeX|to get cross-references right)' refman.log && [ $$latex_count -gt 0 ] ;\
do \
echo "Rerunning latex...." ;\
pdflatex refman ;\
latex_count=`expr $$latex_count - 1` ;\
done
clean:
rm -f *.ps *.dvi *.aux *.toc *.idx *.ind *.ilg *.log *.out *.brf *.blg *.bbl refman.pdf
When running, i get the following message:
MacBook-Pro-13:latex sehlstrom$ make
rm -f *.ps *.dvi *.aux *.toc *.idx *.ind *.ilg *.log *.out *.brf *.blg *.bbl refman.pdf
make: *** No rule to make target `refman.tex', needed by `refman.pdf'. Stop.
How can I get the Makefil thing work?
refman.tex is supposed to be created by Doxygen. I just tested with my installed version, doxygen 1.7.2, and it created a refman.tex.
Make sure you aren't setting any option that says this is a component of a larger project that shouldn't have its own index.

Categories