How can I determine what will be the arguments of the ld command in the build process from inside a script running as "run script build phase"?
I was looking at xcodebuild -dry-run as an option, but then I need to understand what should be the arguments I supply it.
Any idea for a robust solution?
EDIT:
It seems that xcodebuild doesn't support LD and LDPLUSPLUS when the project includes swift source code. So the solution that #fpotter offered doesn't work on project with swift.
Any thoughts?
Xcode doesn't expose a nice way to do this. In a Run Script build phase, all you have to work with are the Xcode build settings provided to you in the environment.
If you really need the entire argument list to ld, there's a hack you can use. With the LD and LDPLUSPLUS build settings, you can make Xcode call a script of your own instead of the real ld. From that script, you could capture the args, call through to the real linker, and then do whatever post processing you like there rather than in a Run Script build phase.
Here's how you could do that:
Create an .xcconfig for your target.
It should look like this:
LD = $(SRCROOT)/ld-wrapper/clang
LDPLUSPLUS = $(SRCROOT)/ld-wrapper/clang++
SRCROOT points to your project's directory. The LDPLUSPLUS line is only required if your app has C++ or ObjC++ code. If you don't want to create an xcconfig, you can also add these as User-Defined build settings via the Xcode UI.
Create wrapper scripts for Xcode to call.
Install a script like this at <your project root>/ld-wrapper/wrapper.sh:
#!/bin/bash
set -o errexit
# Choose which clang to run (clang or clang++) depending on how we're invoked.
# If we're invoked via the 'clang' link, we'll run 'clang'. If we're invoked
# via the 'clang++' link, we'll run 'clang++'.
CLANG_PATH="$DEVELOPER_DIR"/Toolchains/XcodeDefault.xctoolchain/usr/bin/$(basename "$0")
"$CLANG_PATH" "$#"
echo "clang args: $#"
echo "do any post processing here."
Create symlinks for the wrapper script for clang and clang++:
cd <project root>/ld-wrapper
ln -s wrapper.sh clang
ln -s wrapper.sh clang++
That's it. It's ugly, but it works.
I have some Fortran code which uses included modules, and I am wondering what environment variables actually work to set the include path.
To test this out I've been using one of the NAG example codes.
This works:
$ gfortran e04ucfe.f90 -lnag_nag -I/opt/NAG/fll6a23dfl/nag_interface_blocks
This doesn't work:
$ export CPATH=/opt/NAG/fll6a23dfl/nag_interface_blocks
$ gfortran e04ucfe.f90 -lnag_nag
e04ucfe.f90:10.37:
USE nag_library, ONLY : nag_wp
1
Fatal Error: Can't open module file 'nag_library.mod' for reading at (1): No such file or directory
However, the GCC/GFortran documentation states that:
The gfortran compiler currently does not make use of any environment
variables to control its operation above and beyond those that affect
the operation of gcc.
(see https://gcc.gnu.org/onlinedocs/gfortran/Environment-Variables.html and https://gcc.gnu.org/onlinedocs/gcc/Environment-Variables.html#Environment-Variables)
I've tried ltrace-ing the gfortran run and can see it looking at other environment variables (e.g. the regular PATH) but not CPATH.
I can work around this with this:
gfortran e04ucfe.f90 -lnag_nag `echo -I$CPATH | sed -e 's/:/ -I/'`
...but why is this necessary? CPATH works fine with gcc, including for other languages than C/C++, so why doesn't this work with gfortran?
Is there something I can successfully use to the same effect as CPATH for gcc with gfortran, to avoid having to pass multiple -I arguments?
Side note: LIBRARY_PATH works fine in a similar way, for replacing the -L/path/to/libs on the gfortran command-line.
As far as I know gfortran does not support this, which is quite annoying. But it is possible to work around it. If you name the following script gfortran and put it in a directory in your $PATH that is searched before the one with the real gfortran in it, then you will have the behavior you want, with $CPATH transparently being expanded into -I arguments:
#!/bin/bash
/path/to/gfortran $(for i in ${CPATH//:/ }; do echo -I"$i"; done) "$#"
Remember to mark it as executable. For example, if my $PATH is /home/amaurea/local/bin:/usr/local/bin:/usr/bin:/bin and gfortran lives in /usr/local/bin, I would set it up as
$ cd /home/amaurea/local/bin
$ cat <<HERE > gfortran
#!/bin/bash
/usr/bin/gfortran $(for i in ${CPATH//:/ }; do echo -I"$i"; done) "$#"
HERE
$ chmod a+x gfortran
Alternatively you can formulate it as a shell alias, but that would be less flexible and will not work in as many situations.
If you are using Makefiles, I got this to work using the subst command. This replaces the : with -I for each path in the file.
usr/bin/gfortran e04ucfe.f90 -lnag_nag -I${subst :, -I,$(CPATH)}
I want to change the compiler/linker parameters without using NetBeans GUI, i.e. I want every new project I make has already set gcc parameters (like -I and -l -L) in makefile without enter in the project properties window by user interface. I need it for an installation script which already set netbeans for working with fixed library (for example openCV) at first boot. I already tried changing toolchain file like GNU_c.xml and GNU_cpp.xml but without results. Same thing making a GCC alias/bash function before starting netbeans (no inerithance between subshell that netbeans creates for compiling/linking files), also modifying .bashrc file with alias same results.
Is there a way to do this?
You could define an alias in your .bashrc, for example :
$ echo "alias gcc='gcc -l -Wall -Wextra" >> ~/.bashrc
$ source ~/.bashrc
In the case of NetBeans, I don't know if it launches an instance of bash to run gcc but if not, you could define a script as an executable that contains something like (for example):
#!/bin/bash
gcc -l -Wall -Wextra "$#"
# or [gcc "$#"] only if you have define the previous alias in your bashrc
How can I compile/run C or C++ code in a Unix console or a Mac terminal?
If it is a simple single-source program,
make foo
where the source file is foo.c, foo.cpp, etc., you don’t even need a makefile. Make has enough built-in rules to build your source file into an executable of the same name, minus the extension.
Running the executable just built is the same as running any program - but you will most often need to specify the path to the executable as the shell will only search what is in $PATH to find executables, and most often that does not include the current directory (.).
So to run the built executable foo:
./foo
gcc main.cpp -o main.out
./main.out
This is the command that works on all Unix machines... I use it on Linux/Ubuntu, but it works in OS X as well. Type the following command in Terminal.app.
g++ -o lab21 iterative.cpp
-o is the letter O, not zero
lab21 will be your executable file
iterative.cpp is your C++ file
After you run that command, type the following in the terminal to run your program:
./lab21
Two steps for me:
First:
make foo
Then:
./foo
All application execution in a Unix (Linux, Mac OS X, AIX, etc.) environment depends on the executable search path.
You can display this path in the terminal with this command:
echo $PATH
On Mac OS X (by default) this will display the following colon separated search path:
/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/X11/bin
So any executable in the listed directories can by run just by typing in their name. For example:
cat mytextfile.txt
This runs /bin/cat and displays mytextfile.txt to the terminal.
To run any other command that is not in the executable search path requires that you qualify the path to the executable. So say I had an executable called MyProgram in my home directory on Mac OS X I can fully qualify it like so:
/Users/oliver/MyProgram
If you are in a location that is near the program you wished to execute you can qualify the name with a partial path. For example, if MyProgram was in the directory /Users/oliver/MyProject I and I was in my home directory I can qualify the executable name like this, and have it execute:
MyProject/MyProgram
Or say I was in the directory /Users/oliver/MyProject2 and I wanted to execute /Users/oliver/MyProject/MyProgram I can use a relative path like this, to execute it:
../MyProject/MyProgram
Similarly if I am in the same directory as MyProgram I need to use a "current directory" relative path. The current directory you are in is the period character followed by a slash. For example:
./MyProgram
To determine which directory you are currently in use the pwd command.
If you are commonly putting programs in a place on your hard disk that you wish to run without having to qualify their names. For example, if you have a "bin" directory in your home directory for regularly used shell scripts of other programs it may be wise to alter your executable search path.
This can be does easily by either creating or editing the existing .bash_profile file in your home directory and adding the lines:
#!/bin/sh
export PATH=$PATH:~/bin
Here the tilde (~) character is being used as a shortcut for /Users/oliver. Also note that the hash bang (#!) line needs to be the first line of the file (if it doesn't already exist). Note also that this technique requires that your login shell be bash (the default on Mac OS X and most Linux distributions). Also note that if you want your programs installed in ~/bin to be used in preference to system executables your should reorder the export statement as follows:
export PATH=~/bin:$PATH
Do all of this in "Terminal".
To use the G++ compiler, you need to do this:
Navigate to the directory in which you stored the *.cpp file.
cd ~/programs/myprograms/
(the ~ is a shortcut for your home, i.e. /Users/Ryan/programs/myprograms/, replace with the location you actually used.)
Compile it
g++ input.cpp -o output.bin (output.bin can be anything with any extension, really. Extension .bin is just common on Unix.)
There should be nothing returned if it was successful, and that is okay. Generally you get returns on failures.
However, if you type ls, you will see the list of files in the same directory. For example, you would see the other folders, input.cpp and output.bin
From inside the directory, now execute it with ./outbut.bin
A compact way to go about doing that could be:
make foo && ./$_
It is nice to have a one-liner so you can just rerun your executable again easily.
Assuming the current directory is not in the path, the syntax is ./[name of the program].
For example ./a.out
To compile C or C++ programs, there is a common command:
make filename
./filename
make will build your source file into an executable file with the same name. But if you want to use the standard way, You could use the gcc compiler to build C programs and g++ for C++.
For C:
gcc filename.c
./a.out
For C++:
g++ filename.cpp
./a.out
Add the following to get the best warnings, and you will not regret it. If you can, compile using WISE (warning is error).
- Wall -pedantic -Weffc++ -Werror
Step 1 - create a cpp file using the command
touch test.cpp
Step 2 - Run this command
g++ test.cpp
Step 3 - Run your cpp file
./a.out
I am on a new MacBook Pro with the Apple M1 Pro chip. I have my Xcode installed - both IDE and command line tools. This is how it worked for me:
g++ one.cpp -o one
./one
Use a makefile. Even for very small (= one-file) projects, the effort is probably worth it because you can have several sets of compiler settings to test things. Debugging and deployment works much easier this way.
Read the make manual. It seems quite long at first glance, but most sections you can just skim over. All in all, it took me a few hours and made me much more productive.
I found this link with directions:
http://www.wesg.ca/2007/11/how-to-write-and-compile-c-programs-on-mac-os-x/
Basically you do:
gcc hello.c
./a.out (or with the output file of the first command)
In order to compile and run C++ source code from a Mac terminal, one needs to do the following:
If the path of .cpp file is somePath/fileName.cpp, first go the directory with path somePath
To compile fileName.cpp, type c++ fileName.cpp -o fileName
To run the program, type ./fileName
Just enter in the directory in which your .c/.cpp file is.
For compiling and running C code.
gcc filename.c
./a.out filename.c
For compiling and running C++ code.
g++ filename.cpp
./a.out filename.cpp
You need to go into the folder where you have saved your file.
To compile the code: gcc fileName
You can also use the g++ fileName
This will compile your code and create a binary.
Now look for the binary in the same folder and run it.
For running C++ files, run the below command, assuming the file name is "main.cpp".
Compile to make an object file from C++ file.
g++ -c main.cpp -o main.o
Since #include <conio.h> is not supported on macOS, we should use its alternative which is supported on Mac. That is #include <curses.h>. Now the object file needs to be converted to an executable file. To use file curses.h, we have to use library -lcurses.
g++ -o main main.o -lcurses
Now run the executable.
./main
Running a .C file using the terminal is a two-step process.
The first step is to type gcc in the terminal and drop the .C file to the terminal, and then press Enter:
gcc /Desktop/test.c
In the second step, run the following command:
~/a.out
On Windows, I'm cross-compiling a program for ARM/Linux using CodeSourcery's cross-compiler suite. I use MinGW MSYS as my command interpreter, and very often it will mangle my paths and pathnames. For example, to build my program, I invoke
arm-none-linux-gnueabi-gcc.exe -Wall -g \
-Wl,--dynamic-linker=/usr/lib/myrpath/ld-linux.so.3 \
-Wl,-rpath=/usr/lib/myrpath \
-I../targetsysroot/usr/include \
myprogram.c -o myprogram
Of course, I want /usr/lib/myrpath inserted verbatim into the myprogram executable - the ARM Linux target I'm compiling for doesn't use MinGW or MSYS. But here's what ends up going into it:
...
0x0000000f (RPATH) Library rpath: [C:/MinGW/msys/1.0/lib/myrpath]
...
Not exactly what I wanted. If I invoke GCC on the cmd.exe command line directly, I get the right rpath in the executable. If I invoke GCC on the MSYS command line, I get the mangled rpath. If I invoke GCC with a Makefile that is run with make from the cmd.exe command line, I still get a mangled rpath (!)
Any ideas how I might turn off this annoying behavior?
There is a way to suppress the path translation by setting MSYS_NO_PATHCONV=1 in Windows Git MSys or MSYS2_ARG_CONV_EXCL="*" in MSYS2.
Alternatively, you can set the variable only temporarily just for that command by putting the assignment just before the command itself:
MSYS_NO_PATHCONV=1 arm-none-linux-gnueabi-gcc.exe -Wall -g \
-Wl,--dynamic-linker=/usr/lib/myrpath/ld-linux.so.3 \
-Wl,-rpath=/usr/lib/myrpath \
-I../targetsysroot/usr/include \
myprogram.c -o myprogram
I just discovered a neat trick to avoid MSYS/MinGW translating the paths for you.
If you use double-slash to start the path, then MSYS won't translate the path to DOS format. So in OP's example, the -rpath switch should be specified like this:
-Wl,-rpath=//usr/lib/myrpath
All Unix/Linux tools seem to handle such spurious slashes without any problem, so even though your binary's rpath will start with //usr/... I think the loader will do the right thing.
I don't think there's a way to switch this off. MSYS is a fork of an old Cygwin version with a number of tweaks aimed at improved Windows integration, whereby the automatic POSIX path translation when invoking native Windows programs is arguably the most significant. The trouble with that is that it isn't always possible to tell whether an argument is a path or something else, or whether, as in this case, it is in fact a path that nevertheless shouldn't be translated. The translation is guided by a set of heuristics.
You could try using MinGW make instead of MSYS make (yes, they're different things), which is a native Windows build of make without POSIX path support and conversion. Install with mingw-get install mingw32-make and invoke as mingw32-make.
Or you could try Cygwin, ideally with a Cygwin build of the toolchain.
Indeed, in the original MSYS project provided by MinGW.org, there is no way to disable the Posix path conversion.
That's why I made a little fork of the msys-core runtime which supports the MSYS_NO_PATHCONV flag introduced with the Git for Windows fork. In that way, you may use MSYS_NO_PATHCONV environment variable as in the Git for Windows but in the original MinGW/MSYS.
So in summary, to disable this Posix path convesion:
For MSYS2 (built-in): MSYS2_ARG_CONV_EXCL="*"
For Git for Windows (built-in): MSYS_NO_PATHCONV=1
For MinGW.org (with msys-core-extended): MSYS_NO_PATHCONV=1.
export MSYS_NO_PATHCONV=1 was necessary in my case on git-bash on windows (as noted by dx_over_dt above. )
Unfortunately putting two forward slashes for this example doesn't work as expected.
rsync -rvztn --delete --exclude="/application/logs/" ...
I want 'rsync' to exclude files only at /application/logs which is at the top level, hence the leading forward slash. Adding two forward slashes will not cause it to exclude this directory. I have to resort to the less accurate --exclude="application/logs/".