Native Code in your Application or Library¶
Scala Native uses native C and C++ code to interact with the underlyingplatform and operating system. Since the tool chain compiles and linksthe Scala Native system, it can also compile and link C and C++ codeincluded in an application project or a library that supports ScalaNative that includes C and/or C++ source code.
Supported file extensions for native code are.c,.cpp, and.S.
Note that.S files or assembly code is not portable acrossdifferent CPU architectures so conditional compilation would be neededto support more than one architecture. You can also include header fileswith the extensions.h and.hpp.
Applications with Native Code¶
In order to create standalone native projects with native code use thefollowing procedure. You can start with the basic Scala Native template.
Add C/C++ code intosrc/main/resources/scala-native. Thecode can be put in subdirectories as desired inside thescala-native directory. As an example, create a file namedmyapi.c and put it into yourscala-nativedirectory as described above.
longlongadd3(longlongin){returnin+3;}
Next, create a main file as follows:
importscalanative.unsafe._@externobjectmyapi{defadd3(in:CLongLong):CLongLong=extern}objectMain{importmyapi._defmain(args:Array[String]):Unit={valres=add3(-3L)assert(res==0L)println(s"Add3 to -3 =$res")}}
Finally, compile and run this like a normal Scala Native application.
Using libraries with Native Code¶
Libraries developed to target the Scala Native platform can have C, C++,or assembly files included in the dependency. The code is added tosrc/main/resources/scala-native and is published like anormal Scala library. The code can be put in subdirectories as desiredinside thescala-native directory. These libraries canalso be cross built to support Scala/JVM or Scala.js if the Nativeportions have replacement code on the respective platforms.
The primary purpose of this feature is to allow libraries to supportScala Native that need native “glue” code to operate. The current Cinteropt does not allow direct access to macro defined constants andfunctions or allow passing “struct”s from the stack to C functions.Future versions of Scala Native may relax these restrictions making thisfeature obsolete.
Note: This feature is not a replacement for developing or distributingnative C/C++ libraries and should not be used for this purpose.
If the dependency contains native code, Scala Native will identify thelibrary as a dependency that has native code and will unpack thelibrary. Next, it will compile, link, and optimize any native code alongwith the Scala Native runtime and your application code. No additionalinformation is needed in the build file other than the normal dependencyso it is transparent to the library user.
Using a library that contains native code can be used in combinationwith the feature above that allows native code in your application.
Deployment Descriptor for passing settings to the compiler¶
These are features that were added because they areused internally by Scala Native to simplify the build and organize thenative code with their respective projects. These features allow alibrary developer that has native code included with their project tohave better control over compilation settings used for their project. Byadding ascala-native.properties file in the root of your project’sresources/scala-native directory, settings can be added to theproperties file that are added to the compile command.
These features allow the settings described below to apply only to yourlibrary during compilation.
Use the following procedure to use any of the features described below.
Add a Scala Native deployment descriptor to your library.Theproperties file must be named
scala-native.propertiesand must beput in the base of thesrc/main/resources/scala-nativedirectory.
Optional compilation of code if@link is found¶
Libraries developed with “glue” code as described in the previoussection can cause compilation errors when all the following conditionsoccur:
The library and/or header files are not installed
The dependency is in the library users’ build
The code that uses the “glue” code is not called by theapplication or library
If the glue “code” is being called, then the library and headers needto be installed to compile your application otherwise errors areexpected.
Scala Native code can include the annotation@link("z") for examplethat says link with thez library. The compiler will add a link option-lz for this library to the linking phase of the build if the codewith the annotation is used. Seeinterop/Linking with native librariessection for more information.
Thisexperimental feature has been added so the users of yourpublished library can avoid the error described above. Use the followingprocedure to implement this feature.
Add the following content to your new
scala-native.propertiesfiledescribed above. For the purposes of this example assume the library isz. Note that if your library has more than one library you can add acomma-delimited list of libraries. If desired, the comments are notneeded.
# configuration for glue code# defines SCALANATIVE_LINK_Z if @link("z") annnotation is used (found in NIR)# libraries used, comma delimitednir.link.names=z
Now in your native “glue” code add the following. The macro isnamed
SCALANATIVE_LINK_plus the uppercased name of the library.
#ifdef SCALANATIVE_LINK_Z#include<zlib.h>intscalanative_z_no_flush(){returnZ_NO_FLUSH;}// other functions#endif
The feature works by querying the NIR code to see if the user code isusing thez library. If used,-DSCALANATIVE_LINK_Z is passed to thecompiler and your “glue” code is then compiled. Otherwise, the macrokeeps the code inside from compiling.
Adding defines to your library when code is being compiled¶
If your library requires a C preprocessor define then use this featureto add the define-DMY_DEFINE for example to the options passed to thecompiler.
# add defines, do not add -Dpreprocessor.defines=MY_DEFINE, MY_VALUE=2
Add extra include paths for your library¶
Currently, the native code compilation provides an include to yourproject’sresources/scala-native directory. This means that codeneeds to use relative includes. e.g.#include"mylib.h" The buildscans for all files to compile so only relative paths are needed fromyour basescala-native directory
This feature allows you to vendor code, include code as is, that hassystem includes. e.g.#include<libunwind.h> Add the path startingfrom thescala-native path shown above. If you have a more complexsetup, you could also put your code in subdirectories and add paths tothem. Add the paths in Linux/UNIX style and they will be converted asneeded on the Windows platform.
# path to vendored libunwind a base gc pathcompile.include.paths=platform/posix/libunwind, gc
Add C and C++ compiler specific settings¶
You may add specific platform independent settings such as compiler standardsand C++ exception handling settings. Each compilation unit (sub-project) orlibrary is compiled using settings provided by the end user and also providedin the deployment descriptor included in the project. For example, if youinclude C++ code that uses exceptions and provide that setting, you shouldhandle all internal exceptions within the boundaries of that code. The defaultfor the Scala Native build is compiling without using C++ exceptions sothe program could crash if the module is expecting the user to handle C++exceptions.
Clang command-line options tend to allow the last one specified takes effect,overriding any previous conflicting options.
# C optionscompile.c.options=-std=c17compile.cpp.options=-std=c++17, -fcxx-exceptions
Add unique identity to your library for debugging¶
Since these features can apply to libraries that are published, thosecoordinates can be used to identify your library. The example here isfor a Scala Nativejavalib library.
# output via debuggingproject.organization=org.scala-nativeproject.name=javalib
The descriptor and its settings are printed when compiling in debugmode. Use the following command if usingsbt:
sbt--debug
Otherexperimental features may be added for new requirements.
Continue totesting.
