 %CopyrightBegin%

 SPDX-License-Identifier: Apache-2.0

 Copyright Ericsson AB 1996-2025. All Rights Reserved.

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.

 %CopyrightEnd%

******************************************************************************
                                 General
******************************************************************************

There are two different interfaces, the old 'erl_interface' and 'ei'.
The old interface is to depend on the new one, not the other way around.

Erl_interface should be "thread safe", i.e. you should be able to 
handle connections, convert data etc from different threads.

Ei should be "reentrant" or "async safe", i.e. no locks should be set
so that if an ei function is called inside an signal handler there
could be a deadlock.

Try to keep the documented functions, variables and symbols in sync
between

 * Documentation

 * ei.h and erl_interface.h

 * prog/ei_fake_prog.c and prog/erl_fake_prog.c

From time to time do a

  % (cd src; gmake check)

(FIXME this check should be rewritten to a test case)


******************************************************************************
                               Directories
******************************************************************************

 * src/aux/

   Support files for configure described in the next section

 * src/legacy/

   Old erl_interface stuff  FIXME what about thread support etc....?

 * src/connect/

   Create nodes, connections, communication with the other node etc

 * src/decode/

   Simple decode functions

 * src/encode/

   Simple encode functions

 * src/epmd/

   Handle communication with epmd

 * src/misc/

   The rest of the library

 * src/prog/

   erl_call and some test programs for compiling and linking

 * src/not_used/

   Strange, some files are not used....


******************************************************************************
                      Configuration support files
******************************************************************************

The build uses GNU configure and libtool. The libtool and autoconf
package don't need to be installed to configure and build the
sources. But in "maintainer mode" you need them to update some files
in the source distribution.

 * configure.in 

   Used in maintainer mode together with "aclocal.m4" to create
   "configure". "configure.in" is hand written and only need to
   be updated when you change the sources to use new header files
   or C compiler features. You may get some hints about what to
   update using a recent autoconf package and do

     % cd erl_inteface
     % autoscan src

   The result to compare with the current "configure.in" will be
   stored in "src/configure.scan".

 * aclocal.m4

   This file contains macros generated by ??? appended
   with the content of "libtool.m4" in the installed libtool
   package. (FIXME don't know when this is to be updated and
   why it contains so much).

 * src/aux/config.guess
 * src/aux/config.sub

   Used by "configure" to form the subdirectory name
   "cpu-vendor-os".

 * src/aux/install-sh*

   Used if no other BSD compatible install script is found.

 * src/aux/config.h.in

   Used by "configure" as a template for the resulting
   "src/config.h". The file "config.h.in" should be
   updated when "configure.in" is updated because the
   new macros used in your source and this is the file
   where they are listed. You can find out what to update
   using

     % autoheader

 * ltmain.sh

   This is XXX (FIXME what?)

The base for the configure.in script was created with 'autoscan'.
The base for the config.h.in file was created with 'autoheader'.


******************************************************************************
                          Writing source
******************************************************************************

C files in "prog" could include "config.h" directly.

Other C files should include "eidef.h" as the first line of
source. "eidef.h" contains some common constants and macros and
also includes config.h.

In general avoid including other header files from header files.
The exception is to make the prototypes complete to the user of
this library, i.e. to include <stdio.h> to defined FILE or
to include "ei_x_encode" to define the type ei_x_buff.

The function ei_decode_term() (FIXME encode_term?) work on ETERM,
i.e. it converts between the old erl_interface format and ei.
Because of this it is really part of the erl_interface library,
not the ei library.

Use uint8, uint16, uint32, int8, int16, and int32 for types
where size matters ;-) Use uint8 for buffers where we construct
messages.

NOTE!!!! Sending a "char" to macros like isupper(), isalpha() where
the character is > 127 will cause serious problems on some
machines/OS. The reason is that

   'char' may be unsigned, i.e. the Swedish char 'ä' will 
   as a number be negative.

   The implementation of isupper() and others will on some
   machines use an array that is indexed with the incoming
   character code. The Swedish 'ä' will then create an access
   on memory outside the array!

This may give a random value as a result or a segmentation
violation error.


******************************************************************************
                          Global variables
******************************************************************************

There are two reasons we avoid global variables:

  - It is much easier to support threads without them

  - On operating systems like VxWorks the global variable is global
    to all operating system processes.

There are a few global variables that are ok

  ei_x_extra	         This is set to 100 in "ei_x_encode.c" but can be
                         changed for debugging the memory allocation.

  ei_trace_distribution  Enable verbose tracing on stderr.

  errno			 In the non threaded version of the lib this
			 is a global variable.

  __erl_errno 		 This is a global handled by "ei_pthreads.c"

You can check for globals using something like

  % nm -g ei_fake_prog | fgrep OBJT

Global variables but with local scope

  erl_if_ec              Global state, is ok


******************************************************************************
                           The "long long" story
******************************************************************************

There are some functions in the 'ei' library that uses the GCC and
VC++ "long long" type. Unfortunately this can lead to some trouble.

When user code is linked with the "libei.a" the linker will extract
all objects files needed for resolving all symbol references
found. This means that you want to follow the rule that

 * To reduce executable code size we use resonably small C source
   files. One C file is one object file.

 * We try to avoid unessesary dependency. For example currently almost all
   ei_x_encode*() functions are in the same object file. Because they all
   use the corresponding ei_encode*() function this means using one ei_x
   function we will link in "ei_x_encode.o" object file but also all the
   "ei_encode*.o" object files even if they are not used.

But the above is not the real trouble, memory and disk is cheap these
days.  The real trouble is if we compile the 'ei' library using one
compiler, usually GNU cc, and link with another linker than GNU ld or
miss some runtime libraries that the GNU cc generated object files
assume is on the target. For example currently on Solaris some "long
long" operations will create a dependency to a "hidden" library
"libgcc.a". For example in a library not released got references to
"libgcc.a" '__ashldi3'

   % nm -A libei.a | grep '__ashldi3'
   libei.a[decode_longlong.o]: [6]  | 0| 0|NOTY |GLOB |0 |UNDEF |__ashldi3
   libei.a[decode_ulonglong.o]: [5] | 0| 0|NOTY |GLOB |0 |UNDEF |__ashldi3

We can accept that a dependency is created for code linked with
"libei.a" that actually use 'ei' long long functions. But if we
arrange the 'ei' source badly using a non "long long" functions from
'ei' will still link in an object file that need "libgcc.a". One
example is that in plain R9C the ei_x_encode_longlong() function is
located in the file "ei_x_encode.c". So if any "long long" ei_x
function is used we have an unessesary dependency on
"ei_encode_longlong.o" and then need to link with GNU ld on with the
user code or explicitly link with "libgcc.a". The situation can be
visible in plain R9C using

     % nm -A erl_interface-3.4/lib/libei.a | \
	  grep 'longlong' | fgrep -v 'longlong.o'

As an possibly alternative to the current solution we may include the
object files inside the "libgcc.a" archive in the "libei.a" archive.
The "libgcc.a" that is assumed to be used when linking can be found
using

  % gcc -print-libgcc-file-name

Some links about problems and solutions using "libgcc.a"

  http://www.gnu.org/software/gcc/gcc-3.0/libgcc.html
  http://www.gnu.org/software/libc/FAQ.html

The license for "libgcc.a" is a bit special and not located on the
official sites. You have to look in the source file for the "libgcc.a"
you use. The file is named "libgcc.c". If you don't know what gcc that
was used for the build of for example 'r9c' you can use

  % otp_build_env -o r9c | perl -ne '/(gcc-[\d\.]+)/ and print "$1\n"'

Then to view the lincense do

  % less `find /usr/local/share/src/gcc-REL/ -name "libgcc*.c"`


********************************* EOF ****************************************
