Skip to content
This repository has been archived by the owner on Jun 1, 2024. It is now read-only.

NativeLibs: implemented libuart and an example #143

Draft
wants to merge 10 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
151 changes: 151 additions & 0 deletions HelloNativeLibs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
# Native Libraries development using GCC

<a name="TOPICS"></a>

## Contents of this tutorial:
1) Static V.S. Dynamic Native libraries.
2) Simple project compilation using gcc for intel/arm processors V.S. avr-gcc.


## 1) Static V.S. Dynamic Native libraries:

| `Objective` | `Static Native libraries` | `Dynamic Native libraries` |
|-------------|---------------------------|----------------------------|
| Definition | Are object files that includes all the sources for the target compiled project including the external included sources | Are object files that includes the project sources only and symbolic runtime links for the other dynamic libraries |
| Other names | Compile-time libraries | Shared or Runtime libraries |
| Time of linking | At the compile time, the static object files are linked to the project and compiled with the project sources to an executable file | At the runtime, the loader loads the runtime library |

--------------------------------------------------------
## 2) Simple project compilation using intel gcc V.S. avr-gcc:

### Quick Overview:

| `Compiling for intel/arm processors` | `Compiling for avr MCUs` |
|--------------------------------------|--------------------------|
| For intel/arm processors, it's far direct to compile object files and the obejct files are compiled into shared or dynamic libs by default unless specified `-static` compiler option explicitly. | Object files are compiled into static object files by default and the compiler don't support dynamic compilation |

1) Compiling the project into a dynamic/shared (or runtime) library for intel processors:

- The linker gnu (GNU ld) program makes sure to load the dynamic library on application runtime and link the library to the application code automatically, however you can do this also manually and here comes the difference in operation between shared and dynamic libs.

- Here is how to compile the project to a dynamic library:
```bash
function linux_x86_x64() {
local native_sources=$1
if [[ ! -d $linux_natives_dir'/linux-x86-x64' ]]; then
mkdir -p $linux_natives_dir'/linux-x86-x64'
fi
$gcc -fPIC -v $native_sources -shared -o $linux_natives_dir'/linux-x86-x64/'${clibName} \
-I${JAVA__HOME%/*}'/include' \
-I${JAVA__HOME%/*}'/include/linux' \
-I${nativessrc_directory}'/include/linux/' \
-I${nativessrc_directory}'/include/' \

return $?
}
```

- Here is how to link the library to another project and add the library path to the gnu ld:
```bash
function linux_x86_x64() {
local native_sources=$1
if [[ ! -d $output_dir'/linux-x86-x64' ]]; then
mkdir -p $output_dir'/linux-x86-x64'
fi
$gcc -fpie $native_sources -o $output_dir'/linux-x86-x64/'${clibName} \
-I${JAVA__HOME%/*}'/include' \
-I${JAVA__HOME%/*}'/include/linux' \
-I${nativessrc_directory}'/include/linux/' \
-I${nativessrc_directory}'/include' \
-L$linux_libs_root_dir \
-Wl,-rpath,$linux_libs_root_dir \
-l'rs232'

return $?
}
```

- For shared libraries, the linker library can be included in the code using `dlfcn.h` and dynamic libraries can be loaded in code using the absolute file path and you won't need to link the library at the project compile-time.

2) Compiling the project into a static (or compile-time) library for intel processors:

--- WIP ---

3) Compiling the project into a dynamic/shared (or runtime) library for avr MCUs:

```
There is no way to use the dynamic linked libraries on a microcontroller,
since there is no a runtime environment to act upon (the linker program needs a linux machine),
so shared libraries on avr-gcc isn't supported.
```

4) Compiling the project into a static library for avr MCUs:

- Compiling of source files into object files and then packaging the object files into a library archive using the `ar` archive gnu binutil tool:
```bash
function compile() {

cd ${project}'/src/lib/'
nativeSources=(`ls *.c *.cpp *.c++ *.cxx`)

for ((i=0; i<${#nativeSources[@]}; i++)); do
${AVR_HOME}'/bin/avr-g++' \
-c -O -x c++ \
-mmcu=${CHIP} "${project}/src/lib/${nativeSources[i]}" \
-I${AVR_HOME}'/avr/include' \
-I${project}'/src/include' \
-o "${project}/output/${nativeSources[i]}.o"
done

objectcode=`find ${project}'/output/' -name '*.o'`

${AVR_HOME}'/bin/avr-ar' rcs ${output}'.a' $objectcode

${AVR_HOME}'/bin/avr-nm' ${output}'.a' > ${output}'.map'

}
```
- Linking the static library to another project:
```bash
function compile() {
# addLibsTold
# attrs : dir to compile & sharedLib name
nativeSources=`find ${project}'/src/lib' -name '*.c' -o -name '*.cxx' -o -name '*.cpp' -o -name '*.c++'`

# compile to ``.elf`` full program (Executable and Linkable format)
${AVR_HOME}'/bin/avr-g++' -O2 -x c++ \
-mmcu=${CHIP} ${nativeSources} \
-I${AVR_HOME}'/avr/include' \
-I${project}'/src/include' \
-L"${project}/libs/" -l'uart' \
-o ${output}'.elf'

return $?
}
```
- Object files are selectively added to the final code if a call has been made to their source functions in the main source code (to resolve undefined references), otherwise they aren't added to the final elf, even if you have included their function prototypes.

5) Analysis of the compiler command and command options:

- `gcc`: GNU C Collections Toolchains (or GNU C Compiler), is a GNU binutil designed to compile and link C code into static object files and shared object files, object-code is a machine specific generated code, this machine-code is interpreted into hex code when runnning on the CPU, you need to do the interpretation manually on some tiny devices like (MCUs) before uploading using the `object-copy` gnu binutils as follows:
```bash
function convertToHex() {
${AVR_HOME}'/bin/avr-objcopy' -I 'elf32-avr' -O 'ihex' ${output}'.elf' ${output}'.hex'
return $?
}
```
- `g++`: GNU C++ Compiler Toolchains, is the same as gcc with added functionalities to compile and link C++ code into object files.

- `-mmcu=[CHIP]`: Defines the chip (micro-controller unit) used to compile the code, this ensures that the io package is the right package for the target hardware at the compile-time.

- `-I[DIR]`: Adds a directory to the include path.

- `-L[LIB-DIR]`: Adds a library directory to the gnu linker at compile-time.

- `-Wl,-rpath=[DYNAMIC-LIB-DIR]`: Adds a library path (dynamic library) to the runtime path of the linker.

- `-o[OUTPUT]`: Specifies the output object-code.

- `-c`: Commands the gnu compiler to compile the source only to static object files and skip the linking step.

- `-x[LANGUAGE]`: Explicitly specifies the language to use.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/bin/bash

#**
#* Ccoffee Build tool, manual build, alpha-v1.
#*
#* @author pavl_g.
#*#

canonical_link=`readlink -f ${0}`
build_dir=`dirname $canonical_link`

echo "Compiling the project"
echo -e $RESET_Cs
echo "--------Script start--------"

source $build_dir'/compile.sh'

echo -e $RESET_Cs

compile

echo -e $RESET_Cs
echo "--------Script end--------"
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#!/bin/bash

#**
#* Ccoffee Build tool, manual build, alpha-v1.
#*
#* @author pavl_g.
#*#

canonical_link=`readlink -f ${0}`
build_dir=`dirname $canonical_link`

source $build_dir'/variables.sh'

##
# Compile and build native sources.
#
# @echo Script Succeeded if all the commands have passed successfully, exit with error code otherwise.
##
function compile() {
native_sources=`find $nativessrc_directory'/main' $nativessrc_directory'/lib' -name '*.c' -o -name '*.cxx' -o -name '*.cpp' -o -name '*.c++'-o -name '*.ino'`
# tests if the sources exist, then give the current user full permissions on them and compile them
chmod +x $native_sources
# append -lwiringPi for raspberry wiringPi includes
# ${JAVA__HOME%/*} : % returns back to the root base directory of the java home, / is the separator delimiter of the directory string
# compile and build a shared lib for linux systems
if [[ `linux_x86_x64 "${native_sources}"` -eq 0 ]]; then
echo -e "$GREEN_C Task@Build Linux-x86-x64 : Succeeded"
else
echo -e "$RED_C Task@Build Linux-x86-x64 : Failed"
echo -e "$RED_C Exiting Script with error 150"
exit 150
fi
echo -e "$GREEN_C---MajorTask@Build Native Sources : Succeeded---"
}

##
# Build for desktop linux systems
#
# @param nativeSources sources to be compiled for linux desktop.
# @return 0 if command passes, non zero number otherwise with exit code 150 (search the code on repo's wiki).
##
function linux_x86_x64() {
local native_sources=$1
if [[ ! -d $output_dir'/linux-x86-x64' ]]; then
mkdir -p $output_dir'/linux-x86-x64'
fi
$gcc -fpie $native_sources -o $output_dir'/linux-x86-x64/'${clibName} \
-I${JAVA__HOME%/*}'/include' \
-I${JAVA__HOME%/*}'/include/linux' \
-I${nativessrc_directory}'/include/linux/' \
-I${nativessrc_directory}'/include' \
-L$linux_libs_root_dir \
-Wl,-rpath,$linux_libs_root_dir \
-l'rs232'

return $?
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#**
#* Ccoffee Build tool, manual build, alpha-v1.
#*
#* @author pavl_g.
#*#

# print the canonical file name from its symbolic link
canonical_link=`readlink -f ${0}`
#!/bin/bash

# get the directory name of this canonical name
build_dir=`dirname $canonical_link`

# work directories
project_root="${build_dir%/*}"

dynamic_libs_dir="${project_root%/*}"

amd_examples_dir="${dynamic_libs_dir%/*}"

hello_native_libs="${amd_examples_dir%/*}"

# cut the working directory from its end by a one '/' delimiter again
avr_sandbox_root="${hello_native_libs%/*}"

# constant independent
clibName=('HelloRs232.elf')

# native toolchains
gcc='g++-10'

# code sources
nativessrc_directory=$project_root'/src'

# native shared/dynamic libs
linux_libs_root_dir=$project_root'/libs/shared/native/Linux/linux-x86-x64/'
output_dir=$project_root'/output'

source $avr_sandbox_root'/CommonVariables.sh'
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/**
* @file BufferUtils.util
* @author pavl_g.
* @brief Represents utility functions for buffers.
* @version 0.1
* @date 2022-08-24
*
* @copyright
* BSD 3-Clause License
*
* Copyright (c) 2022, Scrappers Team, The AVR-Sandbox Project, Serial4j API.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _BUFFER_UTILS
#define _BUFFER_UTILS

#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>

namespace BufferUtils {

/**
* Nullifies a single buffer cell at the index.
*
* @param buffer the buffer to nullify its cell.
* @param index the index of the buffer cell to nullify.
*/
static inline void nullifyBuffer(void** buffer, int index) {
buffer[index] = NULL;
}

/**
* Frees the memory utilized by the individual buffer cells on a [buffer] with [count] number of cells.
*
* @param buffer the buffer to free its cells.
* @param count the number of cells to free, starting from index zero.
*/
static inline void freeBufferCells(void** buffer, int* count) {
for (int i = 0; i < *count; i++) {
BufferUtils::nullifyBuffer(buffer, i);
free(buffer[i]);
}
}

/**
* @brief Deletes a typified buffer and frees its memory.
*
* @param buffer the buffer to delete.
*/
static inline void deleteBuffer(void* buffer) {
free(buffer);
BufferUtils::nullifyBuffer(&buffer, 0);
}

/**
* @brief Deeply copies the data of the [src] buffer into a new
* buffer and returns it.
*
* @param src the source buffer to get the data from.
* @param count the count length of the buffer.
* @return void** a new buffer with the same data as the source.
*/
static inline void** copy(void** src, int* count) {
void** copy = (void**) calloc(1, sizeof(void**));
for (int i = 0; i < *count; i++) {
/* add new memory on the next array block */
copy[i] = (void*) calloc(1, sizeof(void*));
copy[i] = src[i];
}
return copy;
}

/**
* @brief Re-validates the buffer from [NULL] pointers.
*
* @param buffer the buffer to re-validate.
* @param count the pointers count.
*/
static inline void reValidateBuffer(void** buffer, int* count, int* isProcessed) {
/* get a temp copy from flagged buffer */
void** temp = BufferUtils::copy(buffer, count);
/* free the buffer cells to prepare the buffer to be reinitialized */
BufferUtils::freeBufferCells(buffer, count);
/* re-init the buffer, removing the null pointers */
for (int i = 0, j = 0; i < *count; i++) {
if (temp[i] == NULL) {
printf("%s\n", "zero");
continue;
}
buffer[j] = (void*) calloc(1, sizeof(void*));
buffer[j] = temp[i];
j++;
}
*isProcessed = 1;
/* free the temp buffer */
BufferUtils::freeBufferCells(temp, count);
}
}
#endif
Loading