<?xml version='1.0'?>

<!--
SPDX-FileCopyrightText: Copyright The SCons Foundation (https://scons.org)
SPDX-License-Identifier: MIT
SPDX-FileType: DOCUMENTATION

This file is processed by the bin/SConsDoc.py module.
-->

<!DOCTYPE sconsdoc [
    <!ENTITY % scons SYSTEM "../scons.mod">
    %scons;

    <!ENTITY % builders-mod SYSTEM "../generated/builders.mod">
    %builders-mod;
    <!ENTITY % functions-mod SYSTEM "../generated/functions.mod">
    %functions-mod;
    <!ENTITY % tools-mod SYSTEM "../generated/tools.mod">
    %tools-mod;
    <!ENTITY % variables-mod SYSTEM "../generated/variables.mod">
    %variables-mod;
]>

<chapter id="chap-libraries"
         xmlns="http://www.scons.org/dbxsd/v1.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://www.scons.org/dbxsd/v1.0 http://www.scons.org/dbxsd/v1.0/scons.xsd">
<title>Building and Linking with Libraries</title>

  <para>

  It's often useful to organize large software projects
  by collecting parts of the software into one or more libraries.
  &SCons; makes it easy to create libraries
  and to use them in the programs.

  </para>

  <section>
  <title>Building Libraries</title>

    <para>

    You build your own libraries by specifying &b-link-Library;
    instead of &b-link-Program;:

    </para>

    <scons_example name="libraries_ex1" printme="1">
      <file name="SConstruct" printme="1">
Library('foo', ['f1.c', 'f2.c', 'f3.c'])
      </file>
      <file name="f1.c">
void f1() { printf("f1.c\n"); }
      </file>
      <file name="f2.c">
void f2() { printf("f2.c\n"); }
      </file>
      <file name="f3.c">
void f3() { printf("f3.c\n"); }
      </file>
    </scons_example>

    <para>

    &SCons; uses the appropriate library prefix and suffix for your system.
    So on POSIX or Linux systems,
    the above example would build as follows
    (although &ranlib; may not be called on all systems):

    </para>

    <scons_output example="libraries_ex1" os="posix" suffix="1">
      <scons_output_command>scons -Q</scons_output_command>
    </scons_output>

    <para>

    On a Windows system,
    a build of the above example would look like:

    </para>

    <scons_output example="libraries_ex1" os="win32" suffix="2">
      <scons_output_command>scons -Q</scons_output_command>
    </scons_output>

    <para>

    The rules for the target name of the library
    are similar to those for programs:
    if you don't explicitly specify a target library name,
    &SCons; will deduce one from the
    name of the first source file specified,
    and &SCons; will add an appropriate
    file prefix and suffix if you leave them off.

    </para>

    <section>
    <title>Building Libraries From Source Code or Object Files</title>

      <para>

      The previous example shows building a library from a
      list of source files.
      You can, however, also give the &b-link-Library; call
      object files,
      and it will correctly realize they are object files.
      In fact, you can arbitrarily mix source code files
      and object files in the source list:

      </para>

      <scons_example name="libraries_objects" printme="1">
        <file name="SConstruct" printme="1">
Library('foo', ['f1.c', 'f2.o', 'f3.c', 'f4.o'])
        </file>
        <file name="f1.c">
void f1() { printf("f1.c\n"); }
        </file>
        <file name="f2.o">
object file
        </file>
        <file name="f3.c">
void f3() { printf("f3.c\n"); }
        </file>
        <file name="f4.o">
object file
        </file>
      </scons_example>

      <para>

      And SCons realizes that only the source code files
      must be compiled into object files
      before creating the final library:

      </para>

      <scons_output example="libraries_objects" os="posix" suffix="1">
        <scons_output_command>scons -Q</scons_output_command>
      </scons_output>

      <para>

      Of course, in this example, the object files
      must already exist for the build to succeed.
      See <xref linkend="chap-nodes"></xref>, below,
      for information about how you can
      build object files explicitly
      and include the built files in a library.

      </para>

    </section>

    <section>
    <title>Building Static Libraries Explicitly:  the &b-StaticLibrary; Builder</title>

      <para>

      The &b-link-Library; function builds a traditional static library.
      If you want to be explicit about the type of library being built,
      you can use the synonym &b-link-StaticLibrary; function
      instead of &b-Library;:

      </para>

      <scons_example name="libraries_StaticLibrary" printme="1">
        <file name="SConstruct" printme="1">
StaticLibrary('foo', ['f1.c', 'f2.c', 'f3.c'])
        </file>
      </scons_example>

      <para>

      There is no functional difference between the
      &b-link-StaticLibrary; and &b-Library; functions.

      </para>

    </section>

    <section>
    <title>Building Shared (DLL) Libraries:  the &b-SharedLibrary; Builder</title>

      <para>

      If you want to build a shared library (on POSIX systems)
      or a DLL file (on Windows systems),
      you use the &b-link-SharedLibrary; function:

      </para>

      <scons_example name="libraries_SharedLibrary" printme="1">
        <file name="SConstruct" printme="1">
SharedLibrary('foo', ['f1.c', 'f2.c', 'f3.c'])
        </file>
        <file name="f1.c">
void f1() { printf("f1.c\n"); }
        </file>
        <file name="f2.c">
void f2() { printf("f2.c\n"); }
        </file>
        <file name="f3.c">
void f3() { printf("f3.c\n"); }
        </file>
      </scons_example>

      <para>

      The output on POSIX:

      </para>

      <scons_output example="libraries_SharedLibrary" os="posix" suffix="1">
        <scons_output_command>scons -Q</scons_output_command>
      </scons_output>

      <para>

      And the output on Windows:

      </para>

      <scons_output example="libraries_SharedLibrary" os="win32" suffix="2">
        <scons_output_command>scons -Q</scons_output_command>
      </scons_output>

      <para>

      Notice again that &SCons; takes care of
      building the output file correctly,
      adding the <literal>-shared</literal> option
      for a POSIX compilation,
      and the <literal>/dll</literal> option on Windows.

      </para>

    </section>

  </section>

  <section>
  <title>Linking with Libraries</title>

    <para>

    Usually, you build a library
    because you want to link it with one or more programs.
    You link libraries with a program by specifying
    the libraries in the &cv-link-LIBS; construction variable,
    and by specifying the directory in which
    the library will be found in the
    &cv-link-LIBPATH; construction variable:

    <!-- In the preceding paragraph, the "$" notation for
         LIBS, LIBPATH etc. is used for the first time.
         Maybe some words of explanation would be nice. -->

    </para>

    <scons_example name="libraries_ex2">
      <file name="SConstruct" printme="1">
Library('foo', ['f1.c', 'f2.c', 'f3.c'])
Program('prog.c', LIBS=['foo', 'bar'], LIBPATH='.')
      </file>
      <file name="f1.c">
int main() { printf("Hello, world!\n"); }
      </file>
      <file name="f2.c">
int main() { printf("Hello, world!\n"); }
      </file>
      <file name="f3.c">
int main() { printf("Hello, world!\n"); }
      </file>
      <file name="prog.c">
int main() { printf("Hello, world!\n"); }
      </file>
    </scons_example>

    <para>

    Notice, of course, that you don't need to specify a library
    prefix (like <literal>lib</literal>)
    or suffix (like <literal>.a</literal> or <literal>.lib</literal>).
    &SCons; uses the correct prefix or suffix for the current system.

    </para>

    <para>

    On a POSIX or Linux system,
    a build of the above example would look like:

    </para>

    <scons_output example="libraries_ex2" os="posix" suffix="1">
      <scons_output_command>scons -Q</scons_output_command>
    </scons_output>

    <para>

    On a Windows system,
    a build of the above example would look like:

    </para>

    <scons_output example="libraries_ex2" os="win32" suffix="2">
      <scons_output_command>scons -Q</scons_output_command>
    </scons_output>

    <para>

    As usual, notice that &SCons; has taken care
    of constructing the correct command lines
    to link with the specified library on each system.

    </para>

    <para>

    Note also that,
    if you only have a single library to link with,
    you can specify the library name in single string,
    instead of a Python list,
    so that:

    </para>

    <sconstruct>
Program('prog.c', LIBS='foo', LIBPATH='.')
    </sconstruct>

    <para>

    is equivalent to:

    </para>

    <sconstruct>
Program('prog.c', LIBS=['foo'], LIBPATH='.')
    </sconstruct>

    <para>

    This is similar to the way that &SCons;
    handles either a string or a list to
    specify a single source file.

    </para>

  </section>

  <section>
  <title>Finding Libraries:  the &cv-LIBPATH; Construction Variable</title>

    <para>

    By default, the linker will only look in
    certain system-defined directories for libraries.
    &SCons; knows how to look for libraries
    in directories that you specify with the
    &cv-link-LIBPATH; construction variable.
    &cv-LIBPATH; consists of a list of
    directory names, like so:

    </para>

    <scons_example name="libraries_ex3">
      <file name="SConstruct" printme="1">
Program('prog.c', LIBS = 'm',
                  LIBPATH = ['/usr/lib', '/usr/local/lib'])
      </file>
      <file name="prog.c">
int main() { printf("prog.c\n"); }
      </file>
    </scons_example>

    <para>

    Using a Python list is preferred because it's portable
    across systems.  Alternatively, you could put all of
    the directory names in a single string, separated by the
    system-specific path separator character:
    a colon on POSIX systems:

    </para>

    <sconstruct>
LIBPATH = '/usr/lib:/usr/local/lib'
    </sconstruct>

    <para>

    or a semi-colon on Windows systems:

    </para>

    <sconstruct>
LIBPATH = 'C:\\lib;D:\\lib'
    </sconstruct>

    <para>

    (Note that Python requires that the backslash
    separators in a Windows path name
    be escaped within strings.)

    </para>

    <para>

    When the linker is executed,
    &SCons; will create appropriate flags
    so that the linker will look for
    libraries in the same directories as &SCons;.
    So on a POSIX or Linux system,
    a build of the above example would look like:

    </para>

    <scons_output example="libraries_ex3" os="posix" suffix="1">
      <scons_output_command>scons -Q</scons_output_command>
    </scons_output>

    <para>

    On a Windows system,
    a build of the above example would look like:

    </para>

    <scons_output example="libraries_ex3" os="win32" suffix="2">
      <scons_output_command>scons -Q</scons_output_command>
    </scons_output>
    <!-- The link command is too wide in the PDF version.
         There are some other examples of this throughout the document. -->

    <para>

    Note again that &SCons; has taken care of
    the system-specific details of creating
    the right command-line options.

    </para>

  </section>

</chapter>
