COMPMID-417 Updated build system to not combined objects of the different levels of library

Until now we had:
core = core_obj
arm_compute = core_obj + arm_compute_obj
graph = core_obj + arm_compute_obj + graph_obj
But if an application link against more than one of these libraries then bad things happen.
Added version strings in the runtime library too (As it used to only be in Core objects)
Updated doxygen for how to compile the examples

Change-Id: I7aad6ecf75cfa8dca59f2ea093e13fb0314a3eb4
Reviewed-on: http://mpd-gerrit.cambridge.arm.com/89743
Reviewed-by: Gian Marco Iodice <gianmarco.iodice@arm.com>
Tested-by: Kaizen <jeremy.johnson+kaizengerrit@arm.com>
diff --git a/SConscript b/SConscript
index 15ef090..79f6bf3 100644
--- a/SConscript
+++ b/SConscript
@@ -30,12 +30,12 @@
 Import('env')
 Import('vars')
 
-def build_library(name, sources, static=False):
+def build_library(name, sources, static=False, libs=[]):
     if static:
-        obj = arm_compute_env.StaticLibrary(name, source=sources)
+        obj = arm_compute_env.StaticLibrary(name, source=sources, LIBS = arm_compute_env["LIBS"] + libs)
     else:
         if env['set_soname']:
-            obj = arm_compute_env.SharedLibrary(name, source=sources, SHLIBVERSION = SONAME_VERSION)
+            obj = arm_compute_env.SharedLibrary(name, source=sources, SHLIBVERSION = SONAME_VERSION, LIBS = arm_compute_env["LIBS"] + libs)
 
             symlinks = []
             # Manually delete symlinks or SCons will get confused:
@@ -51,7 +51,7 @@
             Default(clean)
             Depends(obj, clean)
         else:
-            obj = arm_compute_env.SharedLibrary(name, source=sources)
+            obj = arm_compute_env.SharedLibrary(name, source=sources, LIBS = arm_compute_env["LIBS"] + libs)
 
     Default(obj)
     return obj
@@ -191,11 +191,12 @@
 shared_runtime_objects = [arm_compute_env.SharedObject(f) for f in runtime_files]
 static_runtime_objects = [arm_compute_env.StaticObject(f) for f in runtime_files]
 
-arm_compute_a = build_library('arm_compute-static', static_core_objects + static_runtime_objects, static=True)
+arm_compute_a = build_library('arm_compute-static', static_runtime_objects, static=True, libs = [ arm_compute_core_a ])
 Export('arm_compute_a')
 
 if env['os'] != 'bare_metal' and not env['standalone']:
-    arm_compute_so = build_library('arm_compute', shared_core_objects + shared_runtime_objects, static=False)
+    arm_compute_so = build_library('arm_compute', shared_runtime_objects, static=False, libs = [ "arm_compute_core" ])
+    Depends(arm_compute_so, arm_compute_core_so)
     Export('arm_compute_so')
 
 if env['neon'] and env['opencl']:
@@ -208,10 +209,11 @@
     shared_graph_objects = [arm_compute_env.SharedObject(f) for f in graph_files]
     static_graph_objects = [arm_compute_env.StaticObject(f) for f in graph_files]
 
-    arm_compute_graph_a = build_library('arm_compute_graph-static', static_core_objects + static_runtime_objects + static_graph_objects, static=True)
+    arm_compute_graph_a = build_library('arm_compute_graph-static', static_graph_objects, static=True, libs = [ arm_compute_a ])
     Export('arm_compute_graph_a')
 
-    arm_compute_graph_so = build_library('arm_compute_graph', shared_core_objects + shared_runtime_objects + shared_graph_objects, static=False)
+    arm_compute_graph_so = build_library('arm_compute_graph', shared_graph_objects, static=False, libs = [ "arm_compute", "arm_compute_core" ])
+    Depends( arm_compute_graph_so, arm_compute_so)
     Export('arm_compute_graph_so')
 
     graph_alias = arm_compute_env.Alias("arm_compute_graph", [arm_compute_graph_a, arm_compute_graph_so])
diff --git a/SConstruct b/SConstruct
index 50370d3..ba52666 100644
--- a/SConstruct
+++ b/SConstruct
@@ -56,6 +56,7 @@
 )
 
 env = Environment(platform="posix", variables=vars, ENV = os.environ)
+env.Append(LIBPATH = ["#build/%s" % env['build_dir']])
 
 SConsignFile('build/.%s' % env['build_dir'])
 
diff --git a/docs/00_introduction.dox b/docs/00_introduction.dox
index fb174eb..767b902 100644
--- a/docs/00_introduction.dox
+++ b/docs/00_introduction.dox
@@ -480,21 +480,21 @@
 
 To cross compile a NEON example for Linux 32bit:
 
-	arm-linux-gnueabihf-g++ examples/neon_convolution.cpp utils/Utils.cpp -I. -Iinclude -std=c++11 -mfpu=neon -L. -larm_compute -o neon_convolution
+	arm-linux-gnueabihf-g++ examples/neon_convolution.cpp utils/Utils.cpp -I. -Iinclude -std=c++11 -mfpu=neon -L. -larm_compute -larm_compute_core -o neon_convolution
 
 To cross compile a NEON example for Linux 64bit:
 
-	aarch64-linux-gnu-g++ examples/neon_convolution.cpp utils/Utils.cpp -I. -Iinclude -std=c++11 -L. -larm_compute -o neon_convolution
+	aarch64-linux-gnu-g++ examples/neon_convolution.cpp utils/Utils.cpp -I. -Iinclude -std=c++11 -L. -larm_compute -larm_compute_core -o neon_convolution
 
 (notice the only difference with the 32 bit command is that we don't need the -mfpu option and the compiler's name is different)
 
 To cross compile an OpenCL example for Linux 32bit:
 
-	arm-linux-gnueabihf-g++ examples/cl_convolution.cpp utils/Utils.cpp -I. -Iinclude -std=c++11 -mfpu=neon -L. -larm_compute -lOpenCL -o cl_convolution -DARM_COMPUTE_CL
+	arm-linux-gnueabihf-g++ examples/cl_convolution.cpp utils/Utils.cpp -I. -Iinclude -std=c++11 -mfpu=neon -L. -larm_compute -larm_compute_core -lOpenCL -o cl_convolution -DARM_COMPUTE_CL
 
 To cross compile an OpenCL example for Linux 64bit:
 
-	aarch64-linux-gnu-g++ examples/cl_convolution.cpp utils/Utils.cpp -I. -Iinclude -std=c++11 -L. -larm_compute -lOpenCL -o cl_convolution -DARM_COMPUTE_CL
+	aarch64-linux-gnu-g++ examples/cl_convolution.cpp utils/Utils.cpp -I. -Iinclude -std=c++11 -L. -larm_compute -larm_compute_core -lOpenCL -o cl_convolution -DARM_COMPUTE_CL
 
 (notice the only difference with the 32 bit command is that we don't need the -mfpu option and the compiler's name is different)
 
@@ -503,38 +503,38 @@
 
 i.e. to cross compile the "graph_lenet" example for Linux 32bit:
 
-	arm-linux-gnueabihf-g++ examples/graph_lenet.cpp utils/Utils.cpp -I. -Iinclude -std=c++11 -mfpu=neon -L. -larm_compute -larm_compute_graph -lOpenCL -o graph_lenet -DARM_COMPUTE_CL
+	arm-linux-gnueabihf-g++ examples/graph_lenet.cpp utils/Utils.cpp -I. -Iinclude -std=c++11 -mfpu=neon -L. -larm_compute_graph -larm_compute -larm_compute_core -lOpenCL -o graph_lenet -DARM_COMPUTE_CL
 
 i.e. to cross compile the "graph_lenet" example for Linux 64bit:
 
-	aarch64-linux-gnu-g++ examples/graph_lenet.cpp utils/Utils.cpp -I. -Iinclude -std=c++11 -L. -larm_compute -lOpenCL -o graph_lenet -DARM_COMPUTE_CL
+	aarch64-linux-gnu-g++ examples/graph_lenet.cpp utils/Utils.cpp -I. -Iinclude -std=c++11 -L. -larm_compute_graph -larm_compute -larm_compute_core -lOpenCL -o graph_lenet -DARM_COMPUTE_CL
 
 (notice the only difference with the 32 bit command is that we don't need the -mfpu option and the compiler's name is different)
 
 To compile natively (i.e directly on an ARM device) for NEON for Linux 32bit:
 
-	g++ examples/neon_convolution.cpp utils/Utils.cpp -I. -Iinclude -std=c++11 -mfpu=neon -larm_compute -o neon_convolution
+	g++ examples/neon_convolution.cpp utils/Utils.cpp -I. -Iinclude -std=c++11 -mfpu=neon -larm_compute -larm_compute_core -o neon_convolution
 
 To compile natively (i.e directly on an ARM device) for NEON for Linux 64bit:
 
-	g++ examples/neon_convolution.cpp utils/Utils.cpp -I. -Iinclude -std=c++11 -larm_compute -o neon_convolution
+	g++ examples/neon_convolution.cpp utils/Utils.cpp -I. -Iinclude -std=c++11 -larm_compute -larm_compute_core -o neon_convolution
 
 (notice the only difference with the 32 bit command is that we don't need the -mfpu option)
 
 To compile natively (i.e directly on an ARM device) for OpenCL for Linux 32bit or Linux 64bit:
 
-	g++ examples/cl_convolution.cpp utils/Utils.cpp -I. -Iinclude -std=c++11 -larm_compute -lOpenCL -o cl_convolution -DARM_COMPUTE_CL
+	g++ examples/cl_convolution.cpp utils/Utils.cpp -I. -Iinclude -std=c++11 -larm_compute -larm_compute_core -lOpenCL -o cl_convolution -DARM_COMPUTE_CL
 
 To compile natively (i.e directly on an ARM device) the examples with the Graph API, such as graph_lenet.cpp, you need to link the library arm_compute_graph.so also.
 (notice the compute library has to be built with both neon and opencl enabled - neon=1 and opencl=1)
 
 i.e. to cross compile the "graph_lenet" example for Linux 32bit:
 
-	g++ examples/graph_lenet.cpp utils/Utils.cpp -I. -Iinclude -std=c++11 -mfpu=neon -L. -larm_compute -larm_compute_graph -lOpenCL -o graph_lenet -DARM_COMPUTE_CL
+	g++ examples/graph_lenet.cpp utils/Utils.cpp -I. -Iinclude -std=c++11 -mfpu=neon -L. -larm_compute_graph -larm_compute -larm_compute_core -lOpenCL -o graph_lenet -DARM_COMPUTE_CL
 
 i.e. to cross compile the "graph_lenet" example for Linux 64bit:
 
-	g++ examples/graph_lenet.cpp utils/Utils.cpp -I. -Iinclude -std=c++11 L. -larm_compute -larm_compute_graph -lOpenCL -o graph_lenet -DARM_COMPUTE_CL
+	g++ examples/graph_lenet.cpp utils/Utils.cpp -I. -Iinclude -std=c++11 L. -larm_compute_graph -larm_compute -larm_compute_core -lOpenCL -o graph_lenet -DARM_COMPUTE_CL
 
 (notice the only difference with the 32 bit command is that we don't need the -mfpu option)
 
@@ -593,24 +593,24 @@
 To cross compile a NEON example:
 
 	#32 bit:
-	arm-linux-androideabi-clang++ examples/neon_convolution.cpp utils/Utils.cpp -I. -Iinclude -std=c++11 -larm_compute-static -L. -o neon_convolution_arm -static-libstdc++ -pie
+	arm-linux-androideabi-clang++ examples/neon_convolution.cpp utils/Utils.cpp -I. -Iinclude -std=c++11 -larm_compute-static -larm_compute_core-static -L. -o neon_convolution_arm -static-libstdc++ -pie
 	#64 bit:
-	aarch64-linux-android-g++ examples/neon_convolution.cpp utils/Utils.cpp -I. -Iinclude -std=c++11 -larm_compute-static -L. -o neon_convolution_aarch64 -static-libstdc++ -pie
+	aarch64-linux-android-g++ examples/neon_convolution.cpp utils/Utils.cpp -I. -Iinclude -std=c++11 -larm_compute-static -larm_compute_core-static -L. -o neon_convolution_aarch64 -static-libstdc++ -pie
 
 To cross compile an OpenCL example:
 
 	#32 bit:
-	arm-linux-androideabi-clang++ examples/cl_convolution.cpp utils/Utils.cpp -I. -Iinclude -std=c++11 -larm_compute-static -L. -o cl_convolution_arm -static-libstdc++ -pie -lOpenCL -DARM_COMPUTE_CL
+	arm-linux-androideabi-clang++ examples/cl_convolution.cpp utils/Utils.cpp -I. -Iinclude -std=c++11 -larm_compute-static -larm_compute_core-static -L. -o cl_convolution_arm -static-libstdc++ -pie -lOpenCL -DARM_COMPUTE_CL
 	#64 bit:
-	aarch64-linux-android-g++ examples/cl_convolution.cpp utils/Utils.cpp -I. -Iinclude -std=c++11 -larm_compute-static -L. -o cl_convolution_aarch64 -static-libstdc++ -pie -lOpenCL -DARM_COMPUTE_CL
+	aarch64-linux-android-g++ examples/cl_convolution.cpp utils/Utils.cpp -I. -Iinclude -std=c++11 -larm_compute-static -larm_compute_core-static -L. -o cl_convolution_aarch64 -static-libstdc++ -pie -lOpenCL -DARM_COMPUTE_CL
 
 To cross compile the examples with the Graph API, such as graph_lenet.cpp, you need to link the library arm_compute_graph also.
 (notice the compute library has to be built with both neon and opencl enabled - neon=1 and opencl=1)
 
 	#32 bit:
-	arm-linux-androideabi-clang++ examples/graph_lenet.cpp utils/Utils.cpp -I. -Iinclude -std=c++11 -larm_compute-static -larm_compute_graph-static -L. -o graph_lenet_arm -static-libstdc++ -pie -lOpenCL -DARM_COMPUTE_CL
+	arm-linux-androideabi-clang++ examples/graph_lenet.cpp utils/Utils.cpp -I. -Iinclude -std=c++11 -larm_compute_graph-static -larm_compute-static -larm_compute_core-static -L. -o graph_lenet_arm -static-libstdc++ -pie -lOpenCL -DARM_COMPUTE_CL
 	#64 bit:
-	aarch64-linux-android-g++ examples/graph_lenet.cpp utils/Utils.cpp -I. -Iinclude -std=c++11 -larm_compute-static -larm_compute_graph-static -L. -o graph_lenet_aarch64 -static-libstdc++ -pie -lOpenCL -DARM_COMPUTE_CL
+	aarch64-linux-android-g++ examples/graph_lenet.cpp utils/Utils.cpp -I. -Iinclude -std=c++11 -larm_compute_graph-static -larm_compute-static -larm_compute_core-static -L. -o graph_lenet_aarch64 -static-libstdc++ -pie -lOpenCL -DARM_COMPUTE_CL
 
 @note Due to some issues in older versions of the Mali OpenCL DDK (<= r13p0), we recommend to link arm_compute statically on Android.
 
diff --git a/examples/SConscript b/examples/SConscript
index 853a1bb..52d2f26 100644
--- a/examples/SConscript
+++ b/examples/SConscript
@@ -30,7 +30,6 @@
 examples_env = env.Clone()
 
 examples_env.Append(CPPPATH = ["#"])
-examples_env.Append(LIBPATH = ["#build/%s" % env['build_dir']])
 examples_env.Append(LIBPATH = ["#build/%s/opencl-1.2-stubs" % env['build_dir']])
 
 # Build examples
@@ -38,39 +37,44 @@
 
 if env['os'] in ['android', 'bare_metal'] or env['standalone']:
     Import('arm_compute_a')
-    arm_compute_lib = arm_compute_a
+    Import('arm_compute_core_a')
+    arm_compute_libs = [ arm_compute_a, arm_compute_core_a ]
     arm_compute_dependency = arm_compute_a
 else:
     Import('arm_compute_so')
-    arm_compute_lib = "arm_compute"
+    arm_compute_libs = ["arm_compute", "arm_compute_core"]
     arm_compute_dependency = arm_compute_so
 
 if env['opencl'] and env['neon']:
     for file in Glob("./neoncl_*.cpp"):
         example = os.path.basename(os.path.splitext(str(file))[0])
-        prog = examples_env.Program(example, ["{}.cpp".format(example), utils], CPPDEFINES=['ARM_COMPUTE_CL'], LIBS = [arm_compute_lib, "OpenCL"])
+        prog = examples_env.Program(example, ["{}.cpp".format(example), utils], CPPDEFINES=['ARM_COMPUTE_CL'], LIBS = arm_compute_libs +["OpenCL"])
         Depends(prog, [arm_compute_dependency, opencl])
         alias = examples_env.Alias(example, prog)
         Default(alias)
-    Import('arm_compute_graph_a')
-    Import('arm_compute_graph_so')
     if env['os'] == 'android':
-        arm_compute_graph_lib = arm_compute_graph_a
+        Import('arm_compute_graph_a')
+        Import('arm_compute_core_a')
+        Import('arm_compute_a')
+        arm_compute_graph_libs = [ arm_compute_graph_a, arm_compute_a, arm_compute_core_a]
+        graph_dependency = arm_compute_graph_a
     else:
-        arm_compute_graph_lib = "arm_compute_graph"
+        Import('arm_compute_graph_so')
+        arm_compute_graph_libs = ["arm_compute_graph", "arm_compute", "arm_compute_core"]
+        graph_dependency = arm_compute_graph_so
 
     graph_utils = examples_env.Object("../utils/GraphUtils.cpp")
     for file in Glob("./graph_*.cpp"):
         example = os.path.basename(os.path.splitext(str(file))[0])
-        prog = examples_env.Program(example, ["{}.cpp".format(example), utils, graph_utils], CPPDEFINES=['ARM_COMPUTE_CL'], LIBS = [arm_compute_graph_lib, "OpenCL"])
-        Depends(prog, [arm_compute_dependency, opencl])
+        prog = examples_env.Program(example, ["{}.cpp".format(example), utils, graph_utils], CPPDEFINES=['ARM_COMPUTE_CL'], LIBS = arm_compute_graph_libs + ["OpenCL"])
+        Depends(prog, [graph_dependency, opencl])
         alias = examples_env.Alias(example, prog)
         Default(alias)
 
 if env['opencl']:
     for file in Glob("./cl_*.cpp"):
         example = os.path.basename(os.path.splitext(str(file))[0])
-        prog = examples_env.Program(example, ["{}.cpp".format(example), utils], CPPDEFINES=['ARM_COMPUTE_CL'], LIBS = [arm_compute_lib, "OpenCL"])
+        prog = examples_env.Program(example, ["{}.cpp".format(example), utils], CPPDEFINES=['ARM_COMPUTE_CL'], LIBS = arm_compute_libs +["OpenCL"])
         Depends(prog, [arm_compute_dependency, opencl])
         alias = examples_env.Alias(example, prog)
         Default(alias)
@@ -78,7 +82,7 @@
 if env['neon']:
     for file in Glob("./neon_*.cpp"):
         example = os.path.basename(os.path.splitext(str(file))[0])
-        prog = examples_env.Program(example, ["{}.cpp".format(example), utils], LIBS = [arm_compute_lib])
+        prog = examples_env.Program(example, ["{}.cpp".format(example), utils], LIBS = arm_compute_libs)
         Depends(prog, arm_compute_dependency)
         alias = examples_env.Alias(example, prog)
         Default(alias)
diff --git a/src/runtime/Utils.cpp b/src/runtime/Utils.cpp
index 1b06117..81de782 100644
--- a/src/runtime/Utils.cpp
+++ b/src/runtime/Utils.cpp
@@ -28,6 +28,10 @@
 
 using namespace arm_compute;
 
+static const std::string information =
+#include "arm_compute_version.embed"
+    ;
+
 const std::string &arm_compute::string_from_scheduler_type(Scheduler::Type t)
 {
     static std::map<Scheduler::Type, const std::string> scheduler_type_map =
diff --git a/tests/SConscript b/tests/SConscript
index 69c09ca..6b826d0 100644
--- a/tests/SConscript
+++ b/tests/SConscript
@@ -56,11 +56,12 @@
 
 if env['os'] in ['android', 'bare_metal'] or env['standalone']:
     Import("arm_compute_a")
-    test_env.Append(LIBS = [arm_compute_a])
+    Import("arm_compute_core_a")
+    test_env.Append(LIBS = [arm_compute_a, arm_compute_core_a])
     arm_compute_lib = arm_compute_a
 else:
     Import("arm_compute_so")
-    test_env.Append(LIBS = ["arm_compute"])
+    test_env.Append(LIBS = ["arm_compute", "arm_compute_core"])
     arm_compute_lib = arm_compute_so
 
 #FIXME Delete before release
diff --git a/tests/validation_old/SConscript b/tests/validation_old/SConscript
index fdf8e7f..b401f88 100644
--- a/tests/validation_old/SConscript
+++ b/tests/validation_old/SConscript
@@ -59,11 +59,12 @@
 
 if env['os'] in ['android', 'bare_metal'] or env['standalone']:
     Import('arm_compute_a')
-    old_validation_env.Append(LIBS = [arm_compute_a])
+    Import('arm_compute_core_a')
+    old_validation_env.Append(LIBS = [arm_compute_a, arm_compute_core_a])
     arm_compute_lib = arm_compute_a
 else:
     Import('arm_compute_so')
-    old_validation_env.Append(LIBS = ["arm_compute"])
+    old_validation_env.Append(LIBS = ["arm_compute", "arm_compute_core"])
     arm_compute_lib = arm_compute_so
 
 #FIXME Delete before release