Unable to use compiled netlib BLAS on mac OS X - c

I'm trying to make a repository collecting all the examples, tutorials and instructions I could find on the internet for C mathematical and algebra libraries (BLAS, CBLAS, LAPACK, CLAPACK, LAPACKE, ATLAS, openblas, GSL...). but it seems that I just can't get the compiled BLAS .a files working on mac OS X.
So far I have been able to compile BLAS and use it on ubuntu:
BLAS source code from netlib website downloaded and compiled (rename blas_LINUX.a to libblas.a)
Then I can compile the C file on ubuntu using the command below:
gcc foo.c path/to/libblas.a
On my mac OS X (EL Capitan), I can compile BLAS (changing LINUX in the make.inc to DARWIN), but when I try to compile a C code using the command above I get errors like below:
Undefined symbols for architecture x86_64:
"_ddot_", referenced from:
_main in foo-3a35db.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
("ddot" part differs for different functions)
possibilities:
Maybe I'm not compiling the library correctly on mac and there are some differences I'm not aware of
The builtin Accelerate framework of mac OS X is messing up with the compiling process
P.S. Guys I know BLAS/LAPACK is already built into the mac OS X Accelerate framework and I can easily compile using the command gcc foo.c -lblas or gcc foo.c -framework Accelerate but I want to use the compiled .a from netlib. I want to know why it works properly on ubuntu but not mac OS X?
P.S.2. Please notice that I can compile the source code successfully without any errors on mac OS X. I just can use it!
Example code: source
#include <stdio.h>
#include <stdlib.h>
double ddot_(const int *N, const double *a, const int *inca, const double *b, const int *incb);
int main(int argc, char **argv) {
double *a = (double *)malloc(3 * sizeof(double));
a[0] = 1.0;
a[1] = 2.0;
a[2] = 3.0;
// on the stack
double b[3] = {4.0, 5.0, 6.0};
int N = 3, one = 1; // one really doesn't look good in C
double dot_product = ddot_(&N, a, &one, b, &one);
printf(" The dot product is: %f \n", dot_product);
return 0;
}
(edit1) solution:
open make.inc
change the line OPTS = -O3 to OPTS = -O3 -pipe -c and make.
(edit2): better solution:
since I asked this question I have realised that I have been doing everything wrong. Netlib BLAS is actually a collection of fortran routines/subroutines/functions. and the Makefile in the source code just gives us a static library libblas.a which is a collection of all .o object files compiled with gfortran. when we want to compile a C code which want to call one of those routines, we also need to link to the gfortran library libgfortran.* so if you have gcc installed (brew install gcc). look for libgfrotran* (sudo find / -name "libgfortrn.*") and then link your gcc to this folder too. to make it easy I put a Makefile here:
all:
gcc -c foo.c
gcc -o bar.out foo.o -L path/to/libgfortran.*/ -lgfortran -L path/to/libblas.a -lblas
or alternatively compile the code directly with gfortran:
all:
gcc -c foo.c
gfortran -o bar.out foo.o -L path/to/libblas.a -lblas
or simply compile with:
gcc foo.c bar.out -L path/to/libblas.a -lblas -L path/to/libgfortran.*/ -lgfortran
the wonder is how/why the former solution actually worked and why on ubuntu you don't have to link to -lgfortran!

It seems you compiled BLAS library from Netlib with compiler options that changed the mangling scheme of Fortran routines.
By default, Netlib's make.inc uses gfortran to compile BLAS:
$ grep FORTRAN make.inc
# Modify the FORTRAN and OPTS definitions to refer to the
FORTRAN = gfortran
It is compiled without any flags:
gfortran -O3 -pipe -c ddot.f -o ddot.o
and you get the ddot() routine:
$ grep -i ddot ddot.o libblas.a
Binary file ddot.o matches
Binary file libblas.a matches
And you can find it with the command line tools:
$ nm ddot.o libblas.a | grep -i ddot
ddot.o:
0000000000000000 T _ddot_
libblas.a(ddot.o):
0000000000000000 T _ddot_
Your example compiles with the library:
cc ex.c libblas.a
or with the ddot.o file:
cc -pipe ex.c ddot.o
I cannot reproduce your problem. You should use the nm and grep commands to find out what happened to the name of the ddot() routine.
PS. Your code has extra semicolon ; after the end of definition of main().

Related

Couldnot execute the dynamically linked program

Hi I tried doing static library and a shared library with the gnu compiler, here is following code
following is the code for the library
calc_mean.c
double mean(double a, double b){
return (a+b)/2;
}
following is my header file calc_mean.h
double mean(double,double);
Now i started creating static library using following commands
first , calc_mean.c is turned into an object file
gcc -c calc_mean.c -o calc_mean.o
second ,the archiver (ar) is invoked to produce a static
library (named libmean.a) out of the object file calc_mean.o
ar rcs libmean.a calc_mean.o
third, created shared library before that using -fPIC option
created an independant code which is necessary for shared library
gcc -c -fPIC calc_mean.c -o calc_mean.o
now the shared library is created using following command line
gcc -shared -Wl,-soname,libmean.so.1 -o libmean.so.1.0.1 calc_mean.o
finally my main.c file that uses the library is as follows
#include <stdio.h>
#include "calc_mean.h"
int main(int argc, char* argv[]){
double v1,v2,m;
v1 = 5.2;
v2 = 7.9;
m=mean(v1,v2);
printf("The mean of %3.2f and %3.2f is %3.2f\n",v1,v2,m);
return 0;
}
finally I linked the program against static library that generated a statically_linked.exe
gcc -static main.c -L. -lmean -o statically_linked
when dynamically linked, it generated a dynamically_linked.exe with the following command
gcc main.c -o dynamically_linked -L. -lmean
Now when i use the command to execute the dynamically linked program using the following command, Iam getting an error message saying LD_LIBRARY is not recognized as an internal or external command,operable program or batch file
LD_LIBRARY_PATH=.D:\c\project3./dynamically_linked
how can I execute the dynamically linked program?
Your last line suggests that you do all this on windows. But you seem to have followed a step by step guide for linux or another *nix platform.
On windows, a dynamically linked library is in .dll format (not .so) and there's no versioning convention, so the command to create the shared library should look a little different.
Instead of:
gcc -shared -Wl,-soname,libmean.so.1 -o libmean.so.1.0.1 calc_mean.o
do the following on windows:
gcc -shared -Wl,--out-implib,libmean.dll.a -o mean-1.dll calc_mean.o
This creates the library itself named mean-1.dll as well as an import library named libmean.dll.a. The import library (sometimes called .lib instead of .dll.a) on the windows platform is just a stub used during linking of your program, AFAIK MinGW doesn't need it, but other compilers could.
Linking your main program should then work with the same command:
gcc main.c -o dynamically_linked -L. -lmean
And for finding .dll libraries in windows, there is no LD_LIBRARY_PATH -- windows just looks for them in the standard search path, including the directory of the .exe requiring it. IOW, you should be able to just run your program.

a linker issue when learning static library [duplicate]

When I try to build the following program:
#include <stdio.h>
int main(void)
{
printf("hello world\n");
return 0;
}
On OS X 10.6.4, with the following flags:
gcc -static -o blah blah.c
It returns this:
ld: library not found for -lcrt0.o
collect2: ld returned 1 exit status
Has anyone else encountered this, or is it something that noone else has been affected with yet? Any fixes?
Thanks
This won’t work. From the man page for gcc:
This option will not work on Mac OS X unless all libraries (including libgcc.a) have also been compiled with -static. Since neither a static version of libSystem.dylib nor crt0.o are provided, this option is not useful to most people.
Per Nate's answer, a completely static application is apparently not possible - see also man ld:
-static Produces a mach-o file that does not use the dyld. Only used building the kernel.
The problem in linking with static libraries is that, if both a static and a dynamic version of a library are found in the same directory, the dynamic version will be taken in preference. Three ways of avoiding this are:
Do not attempt to find them via the -L and -l options; instead, specify the full paths, to the libraries you want to use, on the compiler or linker command line.
$ g++ -Wall -Werror -o hi /usr/local/lib/libboost_unit_test_framework.a hi.cpp
Create a separate directory, containing symbolic links to the static libraries, use the -L option to have this directory searched first, and use the -l option to specify the libraries you want to use.
$ g++ -Wall -Werror -L ./staticBoostLib -l boost_unit_test_framework -o hi hi.cpp
Instead of creating a link of the same name in a different directory, create a link of a different name in the same directory, and specify that name in a -l argument.
$ g++ -Wall -Werror -l boost_unit_test_framework_static -o hi hi.cpp
You may also try LLVM LLD linker - I did prebuilt version for my two major OSes - https://github.com/VerKnowSys/Sofin-llds
This one allows me to link for exmple: "Qemu" properly - which is impossible with ld preinstalled by Apple.
And last one is - to build GCC yourself with libstdc++ (don't).

Compile and link Fortran and C with ifort and icc

I'm switching from gcc to Intel ifort and icc.
The Fortran code is mostly legacy, likewise the the rest of the system.
The main program is written in C. It handles the I/O and passes everything to a Fortran subroutine.
For now I compile the Fortran part with:
cd fortran
ifort -I../inc -debug full -c *.[fF]
cd ..
For C and linking I tried:
icc -ansi -static -debug full -Wall -o testout \
-I./inc -L./lib\
main.c \
fortran/*.o \
-lifcore -limf -lm\
this gives me:
ld: cannot find -lm
ld: cannot find -lm
ld: cannot find -lc
ld: cannot find -ldl
ld: cannot find -lc
This is mostly copied from the former bash script to compile with gcc.
The -static flag will link all the libraries statically. In that case you need to have a static version (the .a files) of every library. For example, using -lm will search for libm.a. Those libraries are not installed by default, but may be in the -dev or -devel packages of your distribution.
If you only want to link statically the Intel libraries, then you should use -static-intel.
A good trick to avoid static linking is to:
1) Dynamically link your program with -static-intel and -Wl,-rpath=./lib
2) Use ldd to find which libraries your program needs
3) Create a directory lib where you copy all the required dynamic libraries
4) Instead of distributing your code as a single static binary you can disrtibute it as a binary + the lib directory (assuming the licenses of the libraries permit it).
Finally, if you need to try more things, I have succeeded to link an Intel Fortran file with gcc using this command:
$ gcc fortran_file.o c_main_file.o -lifcore -lirc -lcomposerxe_gen_helpers_core_2.3
hope this helps...

Compile a project (say, Emacs) to LLVM bytecode

I cloned the Emacs source, with the intention of compiling to LLVM bytecode. I have been fiddling with Makefile flags for hours, but with no luck. Whenever I Google this, I get completely unrelated results about compiling .el files.
So I ask you this: how can I compile a project like Emacs to LLVM bytecode?
I am on OS X 10.9 Mavericks.
EDIT: I ran these commands:
CC=clang CFLAGS=-emit-llvm ./configure --with-jpeg=no --with-gif=no --with-tiff=no
then
CC=clang CFLAGS=-emit-llvm make
Then I got this error:
xml.c:23:10: fatal error: 'libxml/tree.h' file not found
#include <libxml/tree.h>
^
1 error generated.
When in fact libxml2 is already installed.
-emit-llvm only tells clang that you want any emitted assembly to be in LLVM IR. However, you still need to inform clang that you would like it to emit assembly to start with. This is done by using the -S flag. Additionally, to compile to LLVM bytecode, you need to use llvm-as. Lastly, you will have to do this for every single file, since AFAIK you cannot link LLVM bytecode files together, meaning that you will have many, many LLVM bytecode files.
Enough blabbering though, here's how you would do it for a given file (in the shell, not in the makefile, mind you):
$ clang -c foo.c -S -emit-llvm # additional options as necessary
$ llvm-as foo.s
$ ls
foo.bc foo.c foo.s
Explanation:
$ clang -c foo.c
Compile foo.c by itself without linking.
$ clang -c foo.c -S
Generate assembly and, if no output file is specified, save the results in foo.s.
$ clang -c foo.c -S -emit-llvm
Generate LLVM IR instead of native assembly.
$ llvm-as foo.s
Assemble foo.s and, if no output file is specified, save the results in foo.bc.
EDIT:
Apparently, this works too:
$ clang -c foo.c -emit-llvm -o foo.bc
The -o foo.bc above is because otherwise clang will output a .o file.

Using LLVM linker when using Clang & CMake

What's the best way to tell CMake to use the LLVM linker llvm-link instead of GNU ld as linker? When configuring a project with
CXX=clang++ cmake <args>
the default linker appears to be untouched, remaining usr/bin/ld (on Linux).
Is this possible without using a separate toolchain file?
This turns out to be unrelated to CMake: clang++ uses the system linker by default. For example,
echo "#include <atomic>\n int main() { return 0; }" \
| clang++ -x c++ -std=c++11 -stdlib=libc++ -
uses /usr/bin/ld to link the application. To change the linker to llvm-link, one needs to first emit LLVM byte code, and then call the linker, e.g.:
echo "#include <atomic>\n int main() { return 0; }" \
| clang++ -x c++ -std=c++11 -stdlib=libc++ -S -emit-llvm -o - - \
| llvm-link -o binary -
This bypasses /usr/bin/ld.
As of 3.4, clang looks for the linker (ld) at GCCInstallation.getParentLibPath() + "/../" + GCCInstallation.getTriple().str() + "/bin" before it looks for ld on the path. You should be able to put your linker in /usr/lib/gcc/<arch><sub>-<vendor>-<sys>-<abi>/<version>/ld and have it called by clang in 1 step. To specify this location manually, use the undocumented -B flag. Unfortunately, I don't believe there is a way to alter the name of the linker that is searched for so using ld.gold or lld is going to require a symlink at the aforementioned location.

Resources