I'm trying to get our cross-toolchain (standard Yocto toolchain) working with Bazel. I followed the instructions on https://github.com/bazelbuild/bazel/wiki/Building-with-a-custom-toolchain but the linker fails every time I try to build a simple test program. It says
external/toolchain_e6500/sysroots/x86_64-fslsdk-linux/usr/bin/powerpc64-fsl-linux/../../libexec/powerpc64-fsl-linux/gcc/powerpc64-fsl-linux/4.9.2/real-ld: cannot find /lib64/libc.so.6
external/toolchain_e6500/sysroots/x86_64-fslsdk-linux/usr/bin/powerpc64-fsl-linux/../../libexec/powerpc64-fsl-linux/gcc/powerpc64-fsl-linux/4.9.2/real-ld: cannot find /usr/lib64/libc_nonshared.a
external/toolchain_e6500/sysroots/x86_64-fslsdk-linux/usr/bin/powerpc64-fsl-linux/../../libexec/powerpc64-fsl-linux/gcc/powerpc64-fsl-linux/4.9.2/real-ld: cannot find /lib64/ld64.so.1
The sysroot is set properly. When running the linker command outside of the sandbox (e.g. with --spawn_strategy=standalone or just manually) it works always. The strange thing is that when I use --debug_sandbox and run the emitted command from the command line, it works, too.
I've been debugging this issue for two days now, including straceing the Bazel daemon and comparing the real-ld input but I didn't find anything suspicious.
There must be a difference between the execution environments but I'm out of ideas now. Here is the failing command as printed by --debug_sandbox:
(cd /home/sick/.cache/bazel/_bazel_sick/2a7ae5e27644389520091aa03d045c73/execroot/__main__ && \
exec env - \
PATH=/home/sick/bin:/home/sick/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/home/sick/bin \
PWD=/proc/self/cwd \
TMPDIR=/tmp \
/home/sick/.cache/bazel/_bazel_sick/2a7ae5e27644389520091aa03d045c73/execroot/__main__/_bin/linux-sandbox -t 15 -w /home/sick/.cache/bazel/_bazel_sick/2a7ae5e27644389520091aa03d045c73/sandbox/linux-sandbox/2/execroot/__main__ -w /tmp -w /dev/shm -D -- tools/compiler_e6500/e6500_gcc/powerpc64-fsl-linux-gcc -o bazel-out/e6500-fastbuild/bin/test '--sysroot=external/toolchain_e6500/sysroots/ppc64e6500-fsl-linux' -no-canonical-prefixes -pie -Wl,-z,relro,-z,now -Wl,-S -Wl,#bazel-out/e6500-fastbuild/bin/test-2.params)
You can take a look at the workspace here https://github.com/jasal82/bazel-cross-eval
I can provide the toolchain if needed.
UPDATE 2018-09-25
I did some more investigation after reading the answer regarding the linker script below. Section 4.4.2 in this manual says that
In case a sysroot prefix is configured, and the filename starts with
the / character, and the script being processed was located inside the
sysroot prefix, the filename will be looked for in the sysroot prefix.
Otherwise, the linker will try to open the file in the current
directory.
Obviously the script is not being considered to be located inside the sysroot prefix by ld and thus used literally (i.e. resolved relative to the current dir, probably the sandbox root). That would explain the observed behavior. However, I still don't understand why it does not happen when I run the command manually, i.e. not through the Bazel daemon.
Could this be related to the relative sysroot path used in the CROSSTOOL file? As far as I understood you cannot specify an absolute path to the sysroot due to the sandboxing. What is the recommended way to handle this in Bazel? I would like to avoid having to patch the toolchain.
Have a look at lib.so in your sysroot. It probably looks something like this:
/* GNU ld script
Use the shared library, but some functions are only in
the static library, so try that secondarily. */
OUTPUT_FORMAT(elf64-x86-64)
GROUP ( /lib/x86_64-linux-gnu/libc.so.6 /usr/lib/x86_64-linux-gnu/libc_nonshared.a AS_NEEDED ( /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 )
Change the paths in it to be relative to the directory that libc.so is in. You'll have to perform a similar operation on libm.so and libpthread.so.
The GNU linkers resolve symlinks before evaluating whether a script is within the sysroot. The current Bazel Linux sandbox implementation makes a symlink farm of all an action's inputs. Thus, the libc.so.6 linker script is detected as being in the sysroot outside the sandbox but not within the sandbox.
By default, when running make to compile a C source code file named prog.c
make prog
the default command that executes is
cc prog.c -o prog
Sometimes I really need to include some additional flags. I know that when there are no Makefiles, make relies on some environment variables.
On Ubuntu 14.04, how to configure these variables to change the command that gets executed by default?
Step by step answers will be appreciated!
When no makefile is present (or no rule exists in that makefile) make relies on a default built-in database of rules. Run make -p to get make to spit out all the rules it knows about (in the no makefile case that will be the default ones).
When you look at that list you will find a pattern rule for building C source into object files or executables. Those rules have variables in them (like CFLAGS, LDFLAGS, etc.) that can be used to control exactly what you are trying to. That's why they are there (and are why that default command has such funny spacing, in case you ever wondered about that).
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
I'm running a x86 kernel on an x64 machine. I would like to compile libraries for a i586 processor. During compilation, some libraries use i686 optimization, so want to set -mtunes=i586, -march=i586 and -O3 flags for all of libraries even if they explicitly declare something else in their makefiles.
Somehow I want to set compiler flags permanently...
Regardless of whether you should do this, here's the easiest way to do it:
Create a new file with the following contents:
#!/bin/sh
exec /usr/bin/gcc "$#" -O3 -mtunes=i586 -march=i586
Change /usr/bin/gcc to your actual compiler if that's not right on your system.
Save it as ~/bin/gcc.
Make the new script executable:
chmod +x ~/bin/gcc
Repeat to create another file for g++.
Add ~/bin to the start of your path:
export PATH=~/bin:$PATH
Compile your project. Whenever your new scripts are on the path they will override whatever the makefile says.
Hope that helps.
P.S. The best way to do it (rather than the easiest) would probably be to mess with the compiler's "specs" file, but it's much harder to explain and do.
Just like we specify input flags in the settings of the project in Xcode
Can I make few flags like -O3 or -fopenmp as default flags in command line when I use Terminal.
So that I dont have to type them everytime I compile some c++ fies. Is there a file in the installed gcc or C++ that I can edit to make them default.
Please let me know
thanks
For situations like this you'd probably use a makefile if it's project specific (or other similar automated build management like scons or cmake).
If you want it always on the terminal, you can alias your command to always specify those options, i.e.
alias g++='g++ -O3 -fopenmp'
Note that you said 'terminal' so I assume this is a type of *nix. If that is the case you can also set this into your terminal profile, like ~/.bashrc if you use bash, or ~/.zshrc if you use zsh, etc.