Is there a way to retrieve predefined macros from the GCC preprocessor without having to use temporary files (e.g. using pipes)?
There is a similar question here on StackOverflow, but all its answers make use of the command line, while I need to read mentioned data from within a process.
GCC dump preprocessor defines
Google basically returns a lot of answers to the command line version of the question.
When I try to perform the command line trick of directing output to /dev/null on Linux or NUL on Windows using pipes:
RunAndGetOutput("cpp -dM -E < NUL");
... an error occurs:
cpp.exe: error: <: Invalid argument
cpp.exe: warning: '-x c' last input file has no effect
cpp.exe: fatal error: no input files
compilation terminated.
When I execute the same command from the command line all is fine, and a list of defines it printed.
Is there any way I can fix this problem?
I'm not sure exactly sure how NUL behaves under windows, but I assume it is similar to /dev/null in Unix/Linux: /dev/null in Windows?
On my Ubuntu VM I can do:
cpp -dM -E -xc /dev/null
So I assume under windows you could do something like:
cpp -dM -E -xc NUL
This assumes NUL behaves essentially like an empty file. If the output from type NUL is any indicator here, then this is hopefully the case.
Alternatively, if this doesn't work, you could do the cpp command with redirection within a cmd.exe subshell:
cmd.exe /C "cpp -dM -E < NUL"
From the point of view of RunAndGetOutput(), this is just a single cmd.exe command with a few params passed, and no pipes/redirections. But the cmd.exe shell will interpret the passed string as a command, and importantly will understand how to handle the < redirection correctly.
Since you're calling the cpp preprocessor directly, the -E and -xc options are unnecessary (at least this is the case in Linux), but leaving them there won't do any harm.
Related
First off, I'm using GNU Make 4.3 on Windows 10. I previously tried GNU Make 4.2.1, which gave me the exact same results as 4.3.
Anyway, I have a very simple makefile that does (or at least is intended to do) nothing more than run a simple command and print the output of that command (both stderr and stdout) to the terminal and to a text file.
$(info $$(MAKECMDGOALS) is "$(MAKECMDGOALS)". $$(SHELL) is \
"$(SHELL)". $$(MAKESHELL) is "$(MAKESHELL)". $$(COMSPEC) is "$(COMSPEC)". $$(OS) is "$(OS)".)
TEE := C:\tools\UnixTools\usr\local\wbin\tee.exe
LOG_FILE := C:\Temp\loggy__.txt
.PHONY : meep
all : meep
meep :
$(info Making meep.)
$(info Running command {dir 2>&1 | $(TEE) $(LOG_FILE)}.)
$(shell dir 2>&1 | $(TEE) $(LOG_FILE))
The last line is the one that is giving me trouble. Two things are happening that run counter to my expectations:
While the $(shell ...) call does print the output of the dir command both to my text file and the terminal, the output on the terminal is weirdly formatted. Where normally, dir prints one element per line, here I'm getting the entire output in one line, so it seems like GNU Make (or something else) somehow removes the newline characters from the output before it is shown in the terminal window.
In addition, I'm getting a The system cannot find the file specified. error message (and as usual, Windows is not nice enough to tell me which file it is that it cannot find). Running an echo %errorlevel% in the same CMD shell in which I ran GNU Make confirms that the Make call errored out (exit status is 2).
Weirdly enough, if I run the command dir 2>&1 | C:\tools\UnixTools\usr\local\wbin\tee.exe C:\Temp\loggy__.txt directly in the CMD window, everything works exactly as one would expect, without any errors whatsoever, so I'm thinking there's either something wrong with GNU Make's $(shell ...) function, or I'm using it wrong. Does anyone spot something silly in how I'm trying to use the $(shell ...) function?
I just added --debug=a to my make call to get extra debug output, and I found the following in the output:
Creating temporary batch file C:\Users\mkemp\AppData\Local\Temp\make23400-1.bat
Batch file contents:
#echo off
dir 2>&1 | C:\tools\UnixTools\usr\local\wbin\tee.exe C:\Temp\loggy__.txt
CreateProcess(C:\Users\mkemp\AppData\Local\Temp\make23400-1.bat,C:\Users\mkemp\AppData\Local\Temp\make23400-1.bat,...)
Main thread handle = 00000000000000B4
Cleaning up temporary batch file C:\Users\mkemp\AppData\Local\Temp\make23400-1.bat
Creating temporary batch file C:\Users\mkemp\AppData\Local\Temp\make23400-2.bat
Batch file contents:
#echo off
Volume in drive C is Windows Volume Serial Number is 045A-E422 Directory of C:\tools\UnixTools\usr\local\wbin (... the rest of the output)
CreateProcess(C:\Users\mkemp\AppData\Local\Temp\make23400-2.bat,C:\Users\mkemp\AppData\Local\Temp\make23400-2.bat,...)
So it appears that GNU Make's $(shell ...) function somehow interprets the output produced by the dir call as an additional command it needs to run, which is nonsense, of course.
Using $(shell) is nonsense here. make is acting exactly like you instructed it.
The proper solution is to not add the $(shell ...) function call where it makes no sense.
meep :
$(info Making meep.)
$(info Running command {dir 2>&1 | $(TEE) $(LOG_FILE)}.)
dir 2>&1 | $(TEE) $(LOG_FILE)
Of course, using $(info ...) in a recipe is probably bogus. Inside each recipe, you are running the shell; use the shell's syntax to print diagnostic messages.
meep:
#echo Making meep. >&2
#echo Running command '{dir 2>&1 | $(TEE) $(LOG_FILE)}.' >&2
dir 2>&1 | $(TEE) $(LOG_FILE)
Better yet, don't run make -s and let make itself print what commands it is running, as it does by default (if you don't sprinkle your Makefile with # before all commands to make it harder to debug).
I am new to windows make files.I am trying to understand a few things. How to run commands (DOS commands) from windows mk files. I ran the following command from cmd command prompt--
find testsuite
and it gives proper output. Now I try to run the same from windows mk file as follows -- $(shell find testsuite). However, it gives error "FIND: Parameter format not correct". Is $(shell commandname ...) the correct way or if not what does $(shell...) indicate? Also how to capture the exit status of the command.Adding logline like below after the command doesn't print anything $(warning $(errorlevel)
However, it gives error "FIND: Parameter format not correct".
This is Windows own find utility. It searches for strings in files, kind of grep without regexp :-(. So it requires at least two arguments.
Also how to capture the exit status of the command.
For $(shell ...) function it's in .SHELLSTATUS variable.
I have the following code, which is intended to run a java program on some input, and test that input against a results file for verification.
#!/bin/bash
java Program ../tests/test"$#".tst > test"$#".asm
spim -f test"$#".asm > temp
diff temp ../results/test"$#".out
The gist of the above code is to:
Run Program on a test file in another directory, and pipe the output into an assembly file.
Run a MIPS processor on that program's output, piping that into a file called temp.
Run diff on the output I generated and some expected output.
I made this shell script to help me automate checking of my homework assignment for class. I didn't feel like manually checking things anymore.
I must be doing something wrong, as although this program works with one argument, it fails with more than one. The output I get if I use the $# is:
./test.sh: line 2: test"$#".asm: ambiguous redirect
Cannot open file: `test0'
EDIT:
Ah, I figured it out. This code fixed the problem:
#!/bin/bash
for arg in $#
do
java Parser ../tests/test"$arg".tst > test"$arg".asm
spim -f test"$arg".asm > temp
diff temp ../results/test"$arg".out
done
It turns out that bash must have interpreted a different cmd arg for each time I was invoking $#.
enter code here
If you provide multiple command-line arguments, then clearly $# will expand to a list of multiple arguments, which means that all your commands will be nonsense.
What do you expect to happen for multiple arguments?
I'm trying to use process substitution for an input file to a program, and it isn't working. Is it because some programs don't allow process substitution for input files?
The following doesn't work:
bash -c "cat meaningless_name"
>sequence1
gattacagattacagattacagattacagattacagattacagattacagattaca
>sequence2
gattacagattacagattacagattacagattacagattacagattacagattaca
bash -c "clustalw -align -infile=<(cat meaningless_name) -outfile=output_alignment.aln -newtree=output_tree.dnd"
(Less verbose output, finishing with:
No sequences in file. No alignment!
But the following controls do work:
bash -c "clustalw -align -infile=meaningless_name -outfile=output_alignment.aln -newtree=output_tree.dnd"
(Verbose output, finishing with:
CLUSTAL-Alignment file created [output_alignment.aln]
bash -c "cat <(cat meaningless_name) > meaningless_name2"
diff meaningless_name meaningless_name2
(No output: the two files are the same)
bash -c "clustalw -align -infile=meaningless_name2 -outfile=output_alignment.aln -newtree=output_tree.dnd"
(Verbose output, finishing with:
CLUSTAL-Alignment file created [output_alignment.aln]
Which suggest that process substitution itself works, but that the clustalw program itself doesn't like process substitution - perhaps because it creates a non-standard file, or creates files with an unusual filename.
Is it common for programs to not accept process substitution? How would I check whether this is the issue?
I'm running GNU bash version 4.0.33(1)-release (x86_64-pc-linux-gnu) on Ubuntu 9.10. Clustalw is version 2.0.10.
Process substitution creates a named pipe. You can't seek into a named pipe.
Yes. I've noticed the same thing in other programs. For instance, it doesn't work in emacs either. It gives "File exists but can not be read". And it's definitely a special file, for me /proc/self/fd/some_number. And it doesn't work reliably in either less nor most, with default settings.
For most:
most <(/bin/echo 'abcdef')
and shorter displays nothing. Longer values truncate the beginning. less apparently works, but only if you specify -f.
I find zsh's = much more useful in practice. It's syntactically the same, except = instead of <. But it just creates a temporary file, so support doesn't depend on the program.
EDIT:
I found zsh uses TMPPREFIX to choose the temporary filename. So even if you don't want your real /tmp to be tmpfs, you can mount one for zsh.
Is there a way to log the commands, make invokes to compile a program? I know of the parameters -n and -p, but they either don't resolve if-conditions but just print them out. Or they don't work, when there are calls to 'make' itself in the Makefile.
This
make SHELL="sh -x -e"
will cause the shell (which make invokes to evaluate shell constructs) to print information about what it's doing, letting you see how any conditionals in shell commands are being evaluated.
The -e is necessary to ensure that errors in a Makefile target will be properly detected and a non-zero process exit code will be returned.
You could try to log execve calls with strace
strace -f -e execve make ...
Make writes each command it executes to the console, so
make 2>&1 | tee build.log
will create a log file named build.log as a side effect which contains the same stuff written to the screen. (man tee for more details.)
2>&1 combines standard output and errors into one stream. If you didn't include that, regular output would go into the log file but errors would only go to the console. (make only writes to stderr when a command returns an error code.)
If you want to suppress output entirely in favor of logging to a file, it's even simpler:
make 2>&1 > build.log
Because these just capture console output they work just fine with recursive make.
You might find what you're looking for in the annotated build logs produced by SparkBuild. That includes the commands of every rule executed in the build, whether or not "#" was used to prevent make from printing the command-line.
Your comment about if-conditions is a bit confusing though: are you talking about shell constructs, or make constructs? If you mean shell constructs, I don't think there's any way for you to get exactly what you're after except by using strace as others described. If you mean make constructs, then the output you see is the result of the resolved conditional expression.
Have you tried with the -d parameter (debug)?
Note that you can control the amount of infos with --debug instead. For instance, --debug=a (same as -d), or --debug=b to show only basic infos...