How do different programming languages treat relative paths? - unix

I'll start with an example from PHP. Say I have a file structure like this:
.
└── includes
├── file.php
└── test.php
And say that my code looks like this:
// includes/test.php
require 'file.php';
// includes/file.php
echo 'SUBDIR';
Now, if I run php includes/test.php, I get SUBDIR as output. This is unsurprising.
But say I add a file at ./file.php that says echo 'ROOT!';. Now my tree looks like:
.
├── file.php
└── includes
├── file.php
└── test.php
And when I run php includes/test, it outputs ROOT!. I find this a bit astonishing.
When I think about it, what I find astonishing about it is not necessarily that file.php refers to something in the current working directory, but that before when it didn't find file.php in the current working directory, it looked in includes, relative to the file doing the require. It seems there is a subtle hierarchy to how PHP treats relative paths.
Note that if in includes/test.php I have require './file.php'; instead (a leading ./ where before there was just a "bare" file path), it works as expected IFF the "upper" file.php exists. That is, with a leading ./ it doesn't load includes/file.php and Fatal Errors.
Practically, all this boils down to: Don't use relative paths! Use absolute paths instead! That's not what I'm asking about.
What I'm wondering is, Is this just a UNIX thing? Is it enforced at the OS level, or simply by convention in programming languages? Do other languages behave differently?
Thanks.

It's never (or at least, very rarely) an operating system thing; most (maybe all) operating systems have a fixed an immutable method of resolving relative pathnames. It's almost always either a language thing or an implementation thing; that is, the behavior is documented either in the language standard or in the implementation manual.
For example, the behavior of PHP include and require is documented in the official PHP manual:
Files are included based on the file path given or, if none is given, the include_path specified. If the file isn't found in the include_path, include [and require] will finally check in the calling script's own directory and the current working directory before failing.
If a path is defined — whether absolute (starting with a drive letter or \ on Windows, or / on Unix/Linux systems) or relative to the current directory (starting with . or ..) — the include_path will be ignored altogether. For example, if a filename begins with ../, the parser will look in the parent directory to find the requested file.
Other languages do it differently, of course. For example, in C and C++, #include directives are handled by the preprocessing step; the standards of those language explicitly say that the search for the file to be included is implementation-defined; the actual search rules are defined and documented by the specific compiler.

Related

Robot Framework: does not accept relative path to json file [duplicate]

When creating filepaths and URLs, I noticed that many times the path starts with ./ or ~/.
What is the difference between filepaths that start with ./ and ~/?
What do each of them mean?
For the sake of completeness ...
Just path is a file or directory named path in the current directory.
./path is a file or directory named path in the current directory, with the directory spelled out. The dot directory . represents the current directory, and path is the name of the file or directory within this directory.
~/path is a shorthand for $HOME/path where $HOME is a variable which refers to your home directory. Typically your home directory will be somewhere like /home/you or /Users/you where you is your account name. (The command echo "$HOME" will display your home directory.) The expanded value is an absolute path (unless you have messed up the value of $HOME thoroughly), as indicated by the initial slash.
/path is an absolute path which refers to a file or directory named path which is in the root directory /. Every file on Unix is ultimately somewhere in the directory tree which starts with the root directory.
A file name which begins with $ includes the value of a shell variable in its name (like for example $HOME above); you have to know the value of that variable to determine whether it ends up containing a relative or an absolute path. Similarly, ~ at the beginning of a file name gets replaced ("expanded") by the shell to a different string, as outlined above.
(Technically, it's possible for a file name to begin with a literal dollar sign or tilde, too; you would then have to quote or backslash-escape that character to avoid having the shell expand it to something else. This is rather inconvenient, so these file names tend to be rare in practice.)
In the following exposition, we refer to the result of any such replacements, and ignore the complication of possible quoting.
Every file name which begins with / is an absolute path (aka full path) which explains how to reach a particular node starting from the root directory. For example, /var/tmp/you/reminder.txt refers to a file or directory reminder.txt (probably a file, judging from the name; but Unix doesn't care what you call your files or directories) which is in the directory you which is in the directory tmp which is in the directory var which is in the root directory.
Every file name which doesn't begin with / is a relative path which indicates how to reach a particular file or directory starting from the current directory. The special directory .. is the parent directory (that is, the directory which contains this directory) and the special directory . is the current directory. So path/there refers to the file or directory there inside the directory path in the current directory; and (hover the mouse over the gray area to display the spoiler)
there/.././and/back/.. is a (wicked complicated) way to refer to the directory and in the current directory, where we traverse the there directory and then move back to the current directory; then stay in the current directory; then refer to the directory back inside the directory and, but then move back to the parent directory of that, ending up with ./and.
In addition to ~/ for the current user's home directory, some shells and applications allow the notation ~them/ to refer to the home directory of the user account them. Also, some web server configurations allow each user to have a public web site in their directory ~/public_html and the URL notation http://server/~them/ would serve up the site of the user account them for outside visitors.
The current directory is a convenience which the shell provides so you don't have to type long paths all the time. You can, if you want to.
/bin/ls /home/you/Documents/unix-101/directories.txt
is a longwinded but perfectly valid way to say (assuming you are in your home directory),
ls Documents/unix-101/directories.txt
You could also say
cd Documents/unix-101
ls directories.txt
and until you cd again, all your commands will run in this directory.
See What exactly is current working directory? for a longer exposition of this related concept.
A "directory" is sometimes called a "folder" by people who are not yet old enough to prefer the former.
Tangentially, don't confuse the directory name . with the Bourne shell command which comprises a single dot (also known by its Bash alias source). The command
. ./scriptname
runs the commands from the file ./scriptname in the context of the current shell instance, as opposed to in a separate subshell (which is what just ./scriptname does). In other words, this command line invokes the dot command on a file scriptname in the dot directory.
The Bourne shell (and derivatives like Bash, Zsh, etc) use single quotes to prevent variable expansion and wildcard expansion, and double quotes to permit variable expansion, but inhibit wildcard expansion in a string. The quoting rules on Windows are different, and generally use double quotes to keep whitespace-separated values as a single string (and % instead of $ for variable substitutions).
./ means "starting from the current directory". . refers to the current working directory, so something like ./foo.bar would be looking for a file called foo.bar in the current directory. (As a side note, .. means refers to the parent directory of the current directory. So ../foo.bar would be looking for that file one directory above.)
~/ means "starting from the home directory". This could have different meanings in different scenarios. For example, in a Unix environment ~/foo.bar would be looking for a file called foo.bar in your home directory, something like /home/totzam/foo.bar. In many web applications, ~/foo.bar would be looking for a file called foo.bar in the web application root, something like /var/http/mywebapp/foo.bar.
./ is the current directory
~/ is the home directory of the current user
./ means that path is relative to your current position.
~/ means that path is relative to your home directory.
I will explain a simple example of it. As developers mentioned:
./ is current directory.
~/ is the home directory of the current user.
How both of the file path expressions can help us? Suppose you want to execute a script (.sh) and you're in the same directory where file exists then you can simply do it ./filename.sh
I mostly use ~/ to access my home directory files like .bashrc when I want to add any config in it. It's easier since the file path expression (for home directory) feels much easier and makes accessibility to the file from anywhere, without worrying about the path or changing the path.
. represents current directory
.. represents the parent directory
~ represents the home directory for the current user. Home directory is also represented by HOME env variable. you can do echo $HOME on the shell to see it.
These are generally used to specify relative paths. The / in the end of each notation is a separator that you can use when using these notations together.
Ex:
$ cd ../.. # Go 2 directories backwards
$ cd ~ # Takes you to $HOME directory
$ cd . # Does nothing :) As it literally means go to the directory that you are already present in.
$ cd ~/dir1 $ go to `$HOME/dir1`
On Unix, in any directory if you do ls -a you would see that . and .. will be mentioned (even for empty directory). Like mentioned, these have special meaning and are generated by default in Unix systems and are generally helpful to specify relative paths (i.e, path to a different directory relative to your current directory)
cd command is harmless. So, just play around by combining notations with cd command. You will eventually get a grip of them.

How do I use setwd in a relative way?

Our team uses R scripts in git repos that are shared between several people, across both Mac and Windows (and occasionally Linux) machines. This tends to lead to a bunch of really annoying lines at the top of scripts that look like this:
#path <- 'C:/data-work/project-a/data'
#path <- 'D:/my-stuff/project-a/data'
path = "~/projects/project-a/data"
#path = 'N:/work-projects/project-a/data'
#path <- "/work/project-a/data"
setwd(path)
To run the script, we have to comment/uncomment the correct path variable or the scripts won't run. This is annoying, untidy, and tends to be a bit of a mess in the commit history too.
In past I've got round this by using shell scripts to set directories relative to the script's location and skipping setwd entirely (and then using ./run-scripts.sh instead of Rscript process.R), but as we've got Windows users here, that won't work. Is there a better way to simplify these messy setwd() boilerplates in R?
(side note: in Python, I solve this by using the path library to get the location of the script file itself, and then build relative paths from that. But R doesn't seem to have a way to get the location of the running script's file?)
The answer is to not use setwd() at all, ever. R does things a bit different than Python, for sure, but this is one thing they have in common.
Instead, any scripts you're executing should assume they're being run from a common, top-level, root folder. When you launch a new R process, its working directory (i.e., what getwd() gives) is set to the same folder as the process was spawned from.
As an example, if you had this layout:
.
├── data
│   └── mydata.csv
└── scripts
└── analysis.R
You would run analysis.R from . and analysis.R would reference data/mydata.csv as "data/mydata.csv" (e.g., read.csv("data/mydata.csv, stringsAsFactors = FALSE)).
I would keep your shell scripts or Makefiles that run your R scripts and have the R scripts assume they're being run from the top level of the git repo.
This might look like:
cd . # Whereever `.` above is
Rscript scripts/analysis.R
Further reading:
https://www.tidyverse.org/articles/2017/12/workflow-vs-script/
https://github.com/jennybc/here_here
1) If you are looking for a way to find the path of the currently running script then see:
Rscript: Determine path of the executing script
2) Another approach is to require that users put an option of a prearranged name in their .Rprofile file. Then the script can setwd to that. An attractive aspect of this system is that over time one can forget where various projects are located and with this system one can just look at the .Rprofile file to remind oneself. For example, for projectA each person running the project would put this in their .Rprofile
options(projectA = "...whatever...")
and then the script would start off with:
proj <- getOption("projectA")
if (!is.null(proj)) setwd(proj) else stop("Set option 'projectA' to its directory")
One variation of this is to assume the current directory if projectA is not defined. Although this may seem to be more flexible I personally find the documenting feature of the above code to be a big advantage.
proj <- getOption("projectA")
if (!is.null(proj)) setwd(proj) else cat("Using", getwd(), "\n")
in Python, I solve this by using the path library to get the location of the script file itself, and then build relative paths from that. But R doesn't seem to have a way to get the location of the running script's file?
R itself unfortunately doesn’t have a way for this. But you can achieve the same result in either of two ways:
Use packages instead of scripts where you include code via source. Then you can use the solution outlined in amoeba’s answer. This works because the real issue is that R has no way of telling the source function where to look for scripts.
Use box::use instead of source. The ‘box’ package provides a module system that allows relative imports of code modules. A nice side-effect of this is that the package provides a function that tells you the path of the current script, just like in Python (and, just like in Python, you normally don’t need to use this function directly).

OCaml: How can I get the path to the *current module* / my project's directory?

I'm new to OCaml, but I'm trying to figure out the equivalent of __filename, __dirname from Node. That is, I need to build a path relative to the file containing the code in question.
For reference, I'm working through Ghuloum's IACC: http://ell.io/tt$ocameel
I'm building my first compiler, and I have an utterly-simplistic ‘runtime’ file (in C — temporarily) adjacent to the compiler's source-code. I need to be able to pass the path to this file, as an argument (or a pre-compiled version, I suppose) to gcc or my linker, to have it linked against my compiler's output when I invoke the linker/assembler tooling.
(This may be a stupid question — I'm at a bit of an unknown-unknown here, “how does a compiler get the runtime to the linker”, or something like that. Any commentary about idiomatic solutions to this is welcome, even if it's not a direct answer to the above question!)
If you're running the source file directly via ocaml myfile.ml, Sys.argv.(0) will give you the path to the source file and you can use Filename.dirname to get the directory from that.
If you first compile the source file into an executable and then run the executable, Sys.argv.(0) will give you the name of the executable. In that scenario it's impossible to get the location of the source code (especially if you consider that the person running the executable might not even have the source code on their system).
If you set up your project structure, so that your sources live in src/, your compiled binary in bin/ and the compiled stdlib in lib/, you could just use Filename.dirname Sys.argv.(0) ^ "../lib" as the library path for gcc. This will work whether you run ocaml src/mycompiler.ml, bin/mycompiler or just mycompiler after installing everything to /usr/ or /usr/local/.

how deeply can the source path in windbg be nested?

If I have multiple binaries whose sources are scattered in various subfolders of an overlaying folder, would windbg have access to them if only the topmost folder was included in Source Path? As opposed to having to reference each project folder of each relevant binary separately.
Assuming, of course, that the sources are unique in the mentioned folder structure, i.e. there are no multiple versions of one and the same project, source, etc.
If you specify the parent folder for the source files in source path then it should traverse through the subdirectories to find the source files.
Note that it will perform a signature match against your source files, in the same way that Visual studio will complain that the source files are different to the loaded dlls.
The relative locations of the source files must match the original locations so if your source files are located in a different structure then you will need to do a manual load/browse to specify the location of the source files.
Can’t answer exactly, but I often have 3 top (parent) directories, and each have approximately 4-5 levels of sub directories. No problems. However nothing beats using a source server
Short answer: NO.
From windbg's help:
For each directory in the symbol path, the debugger looks in three
directories. For example, if the symbol path includes the c:\MyDir
directory, and the debugger is looking for symbol information for a
DLL, the debugger first looks in c:\MyDir\symbols\dll, then in
c:\MyDir\dll, and finally in c:\MyDir. The debugger then repeats this
process for each directory in the symbol path. Finally, the debugger
looks in the current directory and then in the current directory with
\dll appended to it. (The debugger appends dll, exe, or sys, depending
on which binaries it is debugging.)
You can move all projects' .pdb files to one folder or change projects properties and setup the linker to create the .pdb file in a specific folder so you have to reference only one.
I've been doing a bit of debugging on this myself. From what I can tell, the relative path of the file found from the SourcePath needs to match part of the end path of the path embedded in the PDB. For example:
I have a file on disk at:
C:\Users\User\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\std\src\sys\windows\thread_local_key.rs
The path of the file embedded in the PDB is:
/rustc/c09a9529c51cde41c1101e56049d418edb07bf71\/library\std\src\sys\windows\thread_local_key.rs
✔ This SourcePath, and any below it, correctly finds the file:
C:\Users\User\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust
❌ This SourcePath, and any above it, does not find the file:
C:\Users\User\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src
Notice how with the failure case, the relative path to the file would begin with library\. The library path component is the first part of the path that is not found in the embedded path. I assume it does a path check for every relative address, recursively:
thread_local_key.rs
windows\thread_local_key.rs
sys\windows\thread_local_key.rs
src\sys\windows\thread_local_key.rs
std\src\sys\windows\thread_local_key.rs
library\std\src\sys\windows\thread_local_key.rs
etc.

IAR Embedded Workbench cannot find files, Pe1696, even though it is searching for them

I am using IAR Embedded workbench 5.51 for MSP430. I am using C99.
I am trying include code from a third party library. I have copied the directory structure of this third party library exactly within a sub-directory in my main project directory. However, when I try to compile I get a bunch of
Fatal Error[Pe1696]: cannot open source file "ThirdPartyLib/Subdir/file.h"
However in the log IAR shows:
searched: "C:\ ... bla bla bla ... \Source\ThirdPartyLib\Subdir\"
The include statements in each of the source files in this library are all like:
#include "ThirdPartyLib/Subdir/someheader.h"
I have attempted to add the path to the C preprocessor by going to:
Project -> Options -> C/C++ Compiler -> Preprocessor
and adding the lines:
$PROJ_DIR$\ThirdPartyLib\
$PROJ_DIR$\ThirdPartyLib\Subdir\
$PROJ_DIR$\ThirdPartyLib\Utils\
I do not have "Multi-file Compilation" checked.
All of the source files in question have been added to the project. I have created groups to mimic the directory structure of the library.
The problem goes away if I change the paths from absolute paths to relative paths such as
#include "somelocalheader.h"
#include "../Utils/someotherheader.h"
But I am dealing with a large number of files and want to modify them as little as possible.
I have never had an issue with this before - does anyone have any idea why this would happen. Is there a simple fix for this so I do not have to scrub every include statement in every c file?
This is essentially what my directory tree looks like:
Source
Debug
Exe
Output.d43
List
blabla.map
Obj
...
Release
...
settings
...
ThirdPartyLib
Subdir
... Third Party Code Files Live Here ...
Utils
... More Third Party Code Files Live Here ...
... My Code Lives Here, Along with the EWP, EWW, etc ...
EDIT #2:
I moved the directory of ThirdPartyLib up a level, because I run doxygen recursively on /Source/ and I realized that it takes doxygen FOREVER, and plus the library has its own API.
Anyway, here is what the structure looks like now:
Working Copy
Source
Debug
Exe
Output.d43
List
blabla.map
Obj
...
Release
...
settings
...
... My Code Lives Here, Along with the EWP, EWW, etc ...
ThirdPartyLib
Subdir
... Third Party Code Files Live Here ...
Utils
... More Third Party Code Files Live Here ...
I have added a group back to my project for ThirdPartyLib with two subgroups SubDir and Utils, and added all of the files from the Subdir and Utils directories to the corresponding subgroups.
Now I have tried to compile this again, and again i am faced with the Pe1696 errors. IAR says:
searched: "C:\...\Working Copy\ThirdPartyLib\SubDir"
Yet it is still not finding the files.
I referred to this post:
http://e2e.ti.com/support/low_power_rf/f/155/t/110195.aspx
I am not sure it is completely relevant, because the directories I am including don't seem to have 'fallen out'. IAR is clearly searching for the files.
But I tried anyway to add the following lines to the preprocessor
$PROJ_DIR$\..\ThirdPartyLib\SubDir
$PROJ_DIR$\..\ThirdPartyLib\utils
This does not seem to help. I get these additional lines in the message log:
searched: "C:\...\Working Copy\Source\..\ThirdPartyLib\SubDir\"
searched: "C:\...\Working Copy\Source\..\ThirdPartyLib\Utils\"
Edit #3
I tried moving the EWW/EWP up a level to "Working Copy" and then readded all of the groups and all of the files... no dice. I am lost here. The part that is most frustrating is that the same library is implemented in another project that was done by some former developers and I am trying to include it the same way. I know this is going to be something trivial, I just don't know what.
If all of the #include references inside the library are of the form #include "ThirdPartyLib/Subdir/file.h", then the root directory where ThirdPartyLib is located should be in the preprocessor include path.
If your directory structure is:
C:\My Project\Source
\ThirdPartyLib
then C:\My Project would be expected to be in the preprocessor include path.
When the compiler searches for include files it will join in turn, each of the include search paths with the path listed in the #include directive until a matching file is found.

Resources