Why $(< file.txt) don't work on makefile? - c

Using the command line I get the desired output
$ ./program $(< file.txt)
./program 1 2 3 4 5
But with a makefile
all: program file.txt
./program $(< file.txt)
#rm -f program
program: program.c
gcc program.c -o program
I get the output
gcc program.c -o program
./program

Because in a makefile, the $(...) syntax is used for variable interpolation. So your makefile tries to expand the value of a makefile variable / environment variable named < file.txt. And if unset, it expands to an empty string.
Proof:
all:
echo $(< file.txt)
and file.txt containing
now it works
Then execute
% env '< file.txt=Hello world' make
echo Hello world
Hello world
i.e. by setting an environment variable named < file.txt to value Hello world , the greeting was printed. The fix is to escape the $ character by doubling it:
all:
echo $$(< file.txt)
and then
% make
echo $(< file.txt)
now it works
Q.E.D.
Finally, while the $() interpolation syntax in POSIX shells, the $(< file.txt) is not but you can replace it with $(cat file.txt) so it works with minimally POSIX-conforming shells. Of course in a makefile you again need to double the dollar, therefore getting the maximally compatible
$$(cat file.txt)
Alternatively you can use the similar makefile facility which is $(shell ), i.e.
$(shell cat file.txt)
would work too... (now with one $). Finally you can read files with $(file ) GNU makefile function too, i.e.
all:
echo $(file <file.txt)
would work alike but wouldn't call shell at all.

The substitution you are trying to use is a Bash feature, but make out of the box runs the regular Bourne shell sh, where this syntax is not available (even when sh is a symlink to Bash, as is still common on some Linux distributions).
Requiring the contents of the file to be specified on the command line looks like a design flaw, anyway; it's probably much better if your C program simply reads and processes standard input (or perhaps accepts a list of file names, and falls back to stdin if none are specified, like many Unix file processing utilities).
If this is just for a test case to run the program with parameters from a file, check out xargs.
xargs ./program <file.txt
If you insist on using Bash-only syntax, add
SHELL=/bin/bash
(or whatever full path is correct on your system); but understand that this limits the portability of your Makefile.
Still, you'll need to double any literal dollar sign which should be passed through and exposed to the shell.

Related

C program with in bash script

I am trying to run C program inside bash, my C program is using the gps device and calculating the distance based on latitude and longitude values. The problem is when i run this C program through bash to get distance, i am not able to redirect its output to any file or variable. i tried this:
output=$(./run)
but it is not working.
to run C code inside bash i am using the following code:
#!/bin/bash
echo 'clear'
echo enter file name
read FILE
gcc -o a.out $FILE -lm
output=$(./a.out)
echo $output
when i do not redirect it shows value:
#!/bin/bash
echo `clear`
echo enter file name
read FILE
gcc -o a.out $FILE -lm
./a.out
[gps values][1]
Can any body help in this?
You don't include the requested debug log, but from your screenshot it looks like your program never exits. It just stays around and writes values forever. Therefore, the capture never reaches the end, so your echo statement never executes.
You should modify your program or invocation so that it will at some point exit.
If you can't modify the program, you can capture e.g. only the first ten lines using one of:
# More canonical way
output=$(./a.out | head -n 10)
# More resilient way, if the program is especially poorly written
output=$( head -n 10 <(./a.out) )
Thank you every one for the comments
It is working now
#!/bin/bash
echo `clear`
echo enter file name
read FILE
gcc -o a.out $FILE -lm
stdbuf -oL ./a.out |
while IFS= read -r line
do
echo "Data: $line"
done
by using the above code
Use -o flag in gcc to create the binary first.
I'll give you an example using "Hello World" code:
~]# cat hw.c
#include <stdio.h>
int main(){
printf("Hello World");
return 0;
}
The bash script:
~]# cat hw.sh
gcc -o hw hw.c
./hw
Then run:
~]# bash hw.sh
Hello World

Getting the compiler default include path into a makefile

I am can run a shell command to grab the default include path from the compiler (and append the -I):
arm-none-eabi-gcc -xc -E -Wp,-v /dev/null 2>&1 | sed -En '/#include <...> search starts here:/,/End of search list./{//!p;};' | sed 's/^ /-I/'
I am trying to add that inside a Makefile:
PROJECT_INC = $(shell arm-none-eabi-gcc -xc -E -Wp,-v /dev/null 2>&1 | sed -En "/#include <...> search starts here:/,/End of search list./{//!p;}" | sed "s/^ /-I/")
Then I get an error:
Makefile:104: *** unterminated call to function `shell': missing `)'. Stop.
I tried to use backticks instead, that does not help. Tried using single-quotes or double-quotes for the sed commands. Most of the similar problems I can find on SO are related to expansion when there is a $ in the command, but it should not be a problem here.
If I cut down the command:
PROJECT_INC = $(shell arm-none-eabi-gcc -xc -E -Wp,-v /dev/null 2>&1 )
Then it seems to be cutting down the output.
The shell would return
ignoring duplicate directory "/Users/mjeanson/miniconda3/envs/project/bin/../lib/gcc/../../lib/gcc/arm-none-eabi/8.3.1/include"
ignoring nonexistent directory "/Users/mjeanson/miniconda3/envs/project/bin/../arm-none-eabi/usr/local/include"
ignoring duplicate directory "/Users/mjeanson/miniconda3/envs/project/bin/../lib/gcc/../../lib/gcc/arm-none-eabi/8.3.1/include-fixed"
ignoring duplicate directory "/Users/mjeanson/miniconda3/envs/project/bin/../lib/gcc/../../lib/gcc/arm-none-eabi/8.3.1/../../../../arm-none-eabi/include"
ignoring nonexistent directory "/Users/mjeanson/miniconda3/envs/project/bin/../arm-none-eabi/usr/include"
#include "..." search starts here:
#include <...> search starts here:
/Users/mjeanson/miniconda3/envs/project/bin/../lib/gcc/arm-none-eabi/8.3.1/include
/Users/mjeanson/miniconda3/envs/project/bin/../lib/gcc/arm-none-eabi/8.3.1/include-fixed
/Users/mjeanson/miniconda3/envs/project/bin/../lib/gcc/arm-none-eabi/8.3.1/../../../../arm-none-eabi/include
End of search list.
# 1 "/dev/null"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/dev/null"
Running this inside the Makefile, it would discard from the first line starting with #include, but otherwise it works. Not sure if that's going to be still be a problem after the piping to the sed command works fine(?)
If that's relevant (and not already obvious in the code snippets above), my environment is using a cross compiler (arm-none-eabi-gcc) and in a conda environment and all running on a Mac.
I don't think it should matter, but the reason why I need to do this is so that I can use some static analysis tool. When compiling the code itself, I do not need to add the default include path.
Bonus: I tried combining the sed commands in one but could not figure out how to do that...
Found the problem... the '#' character in the sed command was causing the issue and cause make to consider everything after as a comment.
For posterity, the fixed command is much easier since the include path start with a ' ':
arm-none-eabi-gcc -xc -E -Wp,-v /dev/null 2>&1 | sed -En '/^ /s/^ /-I/p'
The syntax for the macro expansion in GNU Make is very specific (of make, not to the shell), and normally doesn't take into consideration shell metacharacters like ".
You have included several of these, that mean different things to make (e.g. the :, etc) than they do to the shell.
You'd better to write the complete pipeline into a shell script and then just use the shell script name in the Makefile.
Don't build pipelines with arguments protected by shell quoting, as make doesn't attend to quoting at all.

making sym link to executable file

I have a shell script compileRun that compiles and execute C source file.
#!/bin/sh
gcc bar.c -o ./bar
./bar
what i actualy wish to achieve is when we
ln -s compileRun bar.c
./bar.c
I would like bar.c to be compiled and executed.
I appreciate any help.
I understand what OP wants.
What follows would work only if source files are explicitly stored in a different place than symlinks. A path can be prepended to $0 in the bash script.
Your should replace somefile.c by $0 in your bash script.
This special shell expression returns the name of the file being currently executed. Which would be in your case, bar.c.
For example:
ln execute_c_file my_file.c
./my_file.c
If my_file.c is a running bash script $0 will evaluates to my_file.c.
I suggest you edit your question to clear up the semantic/meaning of your code.

Shell script file for compiling and producing output of C file

I wrote this .sh file to compile any c source file, so that when I run it, it asks for a filename and gcc compiles it and then, runs the executable a.out.
But this doesn't work properly when error is present in .c files. It also shows that a.out is not present. I don't want this error message ( a.out is not present ) but just want to print only the error message generated for the .c files..
Here's the script..
echo `clear`
echo enter file name
read FILE
gcc $FILE
./a.out
echo -e '\n'
If you enable abort-on-error in shell scripts, life will be a lot easier:
#!/bin/sh
set -eu # makes your program exit on error or unbound variable
# ...your code here...
Utilizing builtin rules as an alternative to your script you might want to use make as an alternative to a handcrafted script. To compile file.c and run the generated executable all you need to do is:
make file && ./file
If you don't know it, I strongly suggest you take a look at the make utility as it will ease your work a lot. Managing anything more than a one file project can get really nasty without it.
You can chain compilation and execution commands:
echo `clear`
echo enter file name
read FILE
gcc $FILE && ./a.out
echo -e '\n'
Here, if gcc will fail, the shell will drop the ./a.out command.
You may also protect the file name with double quotes :
#! /bin/bash
clear
echo -n "Enter file name: "
read FILE
gcc -Wall -W "$FILE" && ./a.out
echo
I there hope this is what you were looking it only requires this command:
./compile executableName myCProgram.c -lm
you can place more C files ahead of each others and add more libraries at the end of the line and executableName does not require the .exe
#!/bin/bash
args="$#"
quant=$#
#Copies in case you need the -lm(math library) params
biblio=${args#*-}
#grabs all params except the first one which should be the name of the executable
firstCommand=${*:2:${#args}}
#Remove the "-lm -lc" from firstCommand
firstCommand=${firstCommand%%-*}
printf "\nEXECUTING: gcc -W -Wall -c $firstCommand\n"
#Creates the object file ".o"
gcc -W -Wall -c $firstCommand
#Convert the files names from example.c to example.o
args=${args//.c/.o}
printf "\nEXECUTING: gcc -o $args\n\n"
#Creates the executable
gcc -o $args
printf "\n**Now execute comand: ./$1 **\n\n"

compile a stream of data in C?

Is it possible to compile a stream of data rather than compiling a .c file using gcc? for example, is it possible that instead of having my code stored in any xyz.c file, I can directly compile the code?
Use gcc options -x and -
$ echo -e '#include <stdio.h>\nmain(){puts("Hello world");return 0;}' | gcc -xc -ogarbage - && ./garbage && rm garbage
Hello world
The single line command above is made up of the following parts:
echo -e '#include <stdio.h>\nmain(){puts("Hello world");return 0;}' # "source"
| # pipe
gcc -xc -ogarbage - # compile
&& # and
./garbage # run
&& # and
rm garbage # delete
This may answer you question, though it is rarely useful.
You can create a file, stream the code into it, then create another process(that is, the compiler) giving it the file as an argument. Then create another process(that is, the linker) and it will create an exe for you. And finally you can launch that exe as a new process. But why?!:)

Resources