#include "~/file_name" doesn't compile - c

I have 2 programs:
#include "file1"
int main(void)
{
return (1);
}
where file1 is just an empty file located in the same directory as the program.
Then I have:
#include "~/file2"
int main(void)
{
return (1);
}
where file2 is an empty file but this time is located in my home directory.
The first program compiles, the second program complains and says file not found
Can someone explain what is going on here?

A directive like:
#include "file.h"
searches for a file whose name is file.h. The string ~/file2 in your example is not actually the name of a file. The ~ is expanded by the shell to the path of your home directory; the actual file name is something like /home/username/file2.
The mapping of strings to files can be complex, and it can vary from system to system, but in general there's a fair amount of syntax that's recognized by the shell and converted to a file name, but that doesn't form a file name itself. Variable names like $HOME are similar; you couldn't use $HOME in a #include directive.
Actually
#include "~/file2"
could be valid -- if you have a directory whose name is literally ~ containing a file whose name is file2. That would be legal but confusing.
You could use
#include "/home/username/file2"
but that ties the source to your particular home directory and would make it difficult for anyone else to use ut.
Usually a file to be included should have a name ending in .h, and its location should be either relative to the directory containing the source file, or in one of several locations searched by the compiler.

Related

gcc 5.3.0 for unix reports included c file not found despite it existing

I created a very simple hello world program in C and I'm trying to call a function from an included file. The problem is the gcc program is strange in how it recognizes files.
Suppose the main file is named a.c and the file I want to include is b.c
So in my headers, I add:
#include <./b.c>
and when I run gcc 5.3.0, I receive this error:
./a.c:xx:yy: fatal error: ./b.c: No such file or directory
compilation terminated.
(where xx is the line number of the include line and yy is where the > is located on that line.)
I also tried another idea. I executed gcc while including the library path as follows:
gcc -I./ a.c
and I still get the same error.
In all tests, the file b.c exists in the same folder as a.c is and that I execute gcc from.
Now If I change the include line in the source to the following:
#include </path/to/b.c>
(thereby replacing the relative path with an absolute path) and run gcc, the file is then read for processing.
Is there a way I can change my code so I don't have to constantly specify absolute paths if I need to include multiple custom C files that are all in the same folder as the code that references them?
Like... is there such thing as....
#setlibpath /path/to/my/c/files
#include <./item.c>
#include <./item2.c>
....
#include <./itemn.c>
or do I have to do this....
#include </path/to/my/c/files/item1.c>
#include </path/to/my/c/files/item2.c>
....
#include </path/to/my/c/files/itemn.c>
Converting my comments into an answer.
Use double quotes around the name and the header (source file) will be found. Use angle brackets around system headers. And generally, avoid using ./ (and ../ even more so) in header names. For GCC, see also Include Operation and the following sections.
Also see the POSIX specification for the c99 compiler for the -I option:
Change the algorithm for searching for headers whose names are not absolute pathnames to look in the directory named by the directory pathname before looking in the usual places. Thus, headers whose names are enclosed in double-quotes ("") shall be searched for first in the directory of the file with the #include line, then in directories named in -I options, and last in the usual places. For headers whose names are enclosed in angle brackets (<>), the header shall be searched for only in directories named in -I options and then in the usual places. Directories named in -I options shall be searched in the order specified. If the -I option is used to specify a directory that is one of the usual places searched by default, the results are unspecified.
Note that ./b.c is not an absolute pathname — so the name is appended to a set of directories, and the current directory is not used unless the #include line uses double quotes.

Error at execl: No such file or directory

This is an example that our professor gave us for execl(). There are 2 files in a folder, com1.c looks like
#include <stdio.h>
#include <unistd.h>
int main(){
printf("hello...");
fflush(stdout);
execlp("com2","com2",(char*)NULL);
perror("err at execl");
return 1;
}
and com2.c looks like
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
int main(){
write(1, "...you unicorn ;)",13);
return 0;
}
At runtime it gives me this message:
hello...err at execl: No such file or directory
How can I get "hello...... you unicorn ;" ?
Anticipated thanks.
Make sure that the directory containing com2 is in your PATH environment variable.
PATH=$PATH:/path/to/directory
where /path/to/directory is the directory where you put com2.
You haven't specified what OS you're running ... but, in general, the directory that contains the program you wish to exec should be in your $PATH:
https://linux.die.net/man/3/execlp
The execlp(), execvp(), and execvpe() functions duplicate the actions
of the shell in searching for an executable file if the specified
filename does not contain a slash (/) character. The file is sought in
the colon-separated list of directory pathnames specified in the PATH
environment variable.
If this variable isn't defined, the path list
defaults to the current directory followed by the list of directories
returned by confstr(_CS_PATH). (This confstr(3) call typically returns
the value "/bin:/usr/bin".) If the specified filename includes a slash
character, then PATH is ignored, and the file at the specified
pathname is executed.
Note:
On some other systems, the default path (used when the environment
does not contain the variable PATH) has the current working directory
listed after /bin and /usr/bin, as an anti-Trojan-horse measure. Linux
uses here the traditional "current directory first" default path.

Relative paths from binary file

I have the following folder structure:
bin/ <-binary-file is in here
include/
src/
data/
Makefile
In my code, I use relative paths to my data. So "../data/xml/xmlFile.xml". This is fine if I were executing the binary file from the bin/ folder:
brandonto#computer:~/PATH-TO-PROJECT/bin$ ./binary-file
argv[0] = ./binary-file
dirname(argv[0]) = .
But if I were executing the binary from the main folder (or any other folder that is not the bin/ folder):
brandonto#computer:~/PATH-TO-PROJECT$ bin/binary-file
argv[0] = bin/binary-file
dirname(argv[0]) = bin
The xml files would not be found because "../data" would now go up one directory from the main folder (or whatever folder you are in when executing the program).
How could I make it so that the binary file could be executed from any directory on my system?
To make the question a little more clear:
brandonto#brandonto-Aspire-S3-391:~/cpp-workspace/sdl-projects/sdl-space-shooter/bin$ ~/cpp-workspace/sdl-projects/sdl-space-shooter/bin/SpaceShooter
argv[0] = /home/brandonto/cpp-workspace/sdl-projects/sdl-space-shooter/bin/SpaceShooter
dirname(argv[0]) = /home/brandonto/cpp-workspace/sdl-projects/sdl-space-shooter/bin
brandonto#brandonto-Aspire-S3-391:~/cpp-workspace/sdl-projects/sdl-space-shooter/bin$ cd ..
brandonto#brandonto-Aspire-S3-391:~/cpp-workspace/sdl-projects/sdl-space-shooter$ ~/cpp-workspace/sdl-projects/sdl-space-shooter/bin/SpaceShooter
argv[0] = /home/brandonto/cpp-workspace/sdl-projects/sdl-space-shooter/bin/SpaceShooter
dirname(argv[0]) = /home/brandonto/cpp-workspace/sdl-projects/sdl-space-shooter/bin
Unable to load image ../data/graphics/background/darkPurple.png! SDL_image Error: Couldn't open ../data/graphics/background/darkPurple.png
Unable to load image ../data/graphics/sprites/meteorBrown_big1.png! SDL_image Error: Couldn't open ../data/graphics/sprites/meteorBrown_big1.png
Here, I executed the binary file once from inside the bin/ folder, then once from inside the main folder. The binary ran fine from inside the bin/ folder, but could not find the relative paths to the .png files from inside the main folder.
Probably you are asking a wrong question: the build system has nothing to do with program execution.
However, if you look for an answer, how to make my program to correctly use data, that is located relative to program installation, than here is an answer.
When you program main gets executed, it gets the binary path as the first parameter (index 0). That path can be relative or absolute, but in any case it allows you to find the base directory.
These are also useful links:
How do I find the location of the executable in C?
Finding current executable's path without /proc/self/exe
Here how you can use first argument:
#include <linux/limits.h>
#include <stdio.h>
#include <string.h>
#include <libgen.h>
int main(int argc, char *argv[])
{
char datadir[PATH_MAX];
strncpy(datadir, argv[0], sizeof(datadir));
dirname(datadir);
strncat(datadir, "/../data", sizeof(datadir));
printf("Data dir: %s\n", datadir);
return 0;
}
I believe that you can find your process id (pid) using the getpid command and perform functions to extract the directory in a manner similar to this question on Ask Ubuntu.
I would have the data associated in some way (organizationally) with the bin directory where the executable resides.
Then, when running the routine, if a complete path is provided (noted by checking arg[0]), then you can find the data directory. If a relative path is provided, then search the search path sequentially until you find the executable, and then you can therefore find the data directory.
No pids needed. (I think this is how Python finds its way, or at least how it used to do so.)
I usually solve this with a program setting. In the good old days I would have these settings in a .ini file which would accompany the executable. Some settings would be configurable from within the program, and all could be edited with a text editor. If the file was missing, or any setting missing, they would be created by default.
For the location of the program's data I would use its full absolute path name. For example it might be
Datapath = D:\os50k
and the program then appends individual file names to the path as necessary.
These days in Windows the System Registry is used for this purpose. However your question is tagged Linux which stores settings in various places, including the program directory.
This question, and this question describe the process more fully.
If your paths can be determined at build time, (i.e. your project will never need to be installed to another directory,) you can inject the path through the build system as a preprocessor definition. Here's an example with CMake:
file(TO_CMAKE_PATH "${PROJECT_BINARY_DIR}/resources" RESOURCE_DIR) # Normalize Windows/Linux paths
add_custom_command(
TARGET my_target POST_BUILD
COMMAND ${CMAKE_COMMAND} ARGS -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/resources ${RESOURCE_DIR}
)
target_compile_definitions(my_target PUBLIC RESOURCE_DIR=${RESOURCE_DIR})
.
#define VAL(x) #x
#define STR(x) VAL(x)
const char* my_resource = STR(RESOURCE_DIR) "/my_resource.abc";

How do I access a header file/find its location?

I'm running through some source code that I was given, but I'm accessing it through SSH. It includes a header file or two which i'm not familiar with and I don't believe is part of the C libraries that are provided.
Is there a way that I can do this? Where should I look in the system files to see what this header file contains?
The top of the file reads:
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include "support.h"
But there is no support.h file in the .c file's directory...where could it be?
You can try find <project-root-dir> -name support.h. It's likely to be in a directory like include, but of course could be anything. Also if it builds, you can look at the compile command and see what -I directories are supplied. As a last resort you can try locate support.h or find / -name support.h.
Apart form searching the filesystem with either find or locate, if you have access to the makefile, you should find the information in the compilation line after in a -I argument.

Relative paths in C

I have a C program that uses some resources located in the same directory as the executable. When I execute the program from a random working directory (not the directory where the program is located) the resources don't load, because the relative path I use in the code is not the path where the executable is. How can I solve this nicely?
Pass the path of the directory that contains the resources to the program as an argument and either:
change the current directory of the process to the directory (chdir() on Unix and SetCurrentDirectory() on Windows), or
construct absolute paths to the resources
If it is Windows, as the comment on the question suggests, you can obtain the path of the exe using GetModuleFileName(), extract the directory from it and avoid having to provide an argument to the program. Then either of two options listed would allow the program to be executed from anywhere and still locate its resources.
For anyone happening upon this old question in the future as I just did:
The program (at least in linux) keeps the command it was called by as the first argument of int main argument list.
e.g.
In this example we will drill down a couple of directories to get to our program, resulting in the following call command user#PC:~$ ./foo/bar/awesome_program.x86_64.
The program (code below) will print ./foo/bar/awesome_program.x86_64.
Since we have that string as a variable, it should be rather simple to construct relative paths from it, only replacing the end of that string with paths relative to the executable.
working code:
#include <stdio.h>
int main (int argc, char **argv)
{
printf("calling path: %s\n", argv[0]);
return 0;
}

Resources