Advanced Build Configuration
============================

## Table of Contents
- [Building With CMake](#building-with-cmake)
- [Optional Components](#optional-components)
- [Imaging Plugins](#imaging-plugins)
- [Third Party Plugins](#third-party-plugins)
- [Tests](#tests)
- [Other Build Options](#other-build-options)
- [USD Developer Options](#usd-developer-options)
- [Optimization Options](#optimization-options)
- [Linker Options](#linker-options)

## Building With CMake

Users may specify libraries to build USD against and other build options by 
passing arguments when running cmake. Documentation for these arguments
are below.

Some examples:

#### On Linux 

```bash
cmake                                       \
-DTBB_ROOT_DIR=/path/to/tbb                 \    
-DOPENEXR_LOCATION=/path/to/openexr         \
-DOPENSUBDIV_ROOT_DIR=/path/to/opensubdiv   \
-DPTEX_LOCATION=/path/to/ptex               \
-DOIIO_LOCATION=/path/to/openimageio        \
-DBOOST_ROOT=/path/to/boost                 \
/path/to/USD/source

cmake --build . --target install -- -j <NUM_CORES>
```

#### On OS X

The following will generate an Xcode project that can be used to build USD.

```bash
cmake                                       \
-G "Xcode"                                  \
-DTBB_ROOT_DIR=/path/to/tbb                 \    
-DOPENEXR_LOCATION=/path/to/openexr         \
-DOPENSUBDIV_ROOT_DIR=/path/to/opensubdiv   \
-DPTEX_LOCATION=/path/to/ptex               \
-DOIIO_LOCATION=/path/to/openimageio        \
-DBOOST_ROOT=/path/to/boost                 \
/path/to/USD/source

cmake --build . --target install -- -j <NUM_CORES>
```

#### On Windows

The following will generate a Visual Studio 2015 solution that can be used to 
build USD.

```cmd.exe
"C:\Program Files\CMake\bin\cmake.exe"      ^
-G "Visual Studio 14 Win64"                 ^
-DTBB_ROOT_DIR=C:\path\to\tbb               ^
-DOPENEXR_LOCATION=C:\path\to\openexr       ^
-DOPENSUBDIV_ROOT_DIR=C:\path\to\opensubdiv ^
-DPTEX_LOCATION=C:\path\to\ptex             ^
-DOIIO_LOCATION=C:\path\to\openimageio      ^
-DBOOST_ROOT=C:\path\to\boost               ^
\path\to\USD\source

cmake --build . --target install -- /m:%NUMBER_OF_PROCESSORS%
```  

## Optional Components

USD contains several optional components that are enabled by default
but may be disabled when invoking cmake. Disabling these components
removes the need for their dependencies when building USD.

##### Documentation

Doxygen documentation can optionally be generated by specifying the cmake flag 
```PXR_BUILD_DOCUMENTATION=TRUE```. The additional dependencies that must
be supplied for enabling documentation generation are: 

| Dependency Name    | Description                                                             | Version |
| ------------------ |-----------------------------------------------------------------------  | ------- |
| DOXYGEN_EXECUTABLE | The location of Doxygen                                                 | 1.8.6   |
| DOT_EXECUTABLE     | The location of Dot(from GraphViz).                                     | 2.3     |


##### Imaging

This component contains Hydra, a high-performance graphics rendering engine.

Disable this component by specifying the cmake flag ```PXR_BUILD_IMAGING=FALSE``` when 
invoking cmake. Disabling this component will also disable the [USD Imaging](#usd-imaging)
component and any [Imaging Plugins](#imaging-plugins).

Support for Ptex can optionally be disabled by specifying the cmake flag
```PXR_ENABLE_PTEX_SUPPORT=FALSE```.


##### USD Imaging

This component provides the USD imaging delegates for Hydra, as well as
usdview, a standalone native viewer for USD files.

Disable this component by specifying the cmake flag ```PXR_BUILD_USD_IMAGING=FALSE``` when
invoking cmake. Enabling this component will enable the [Imaging](#imaging)
component.

## Imaging Plugins

Hydra's rendering functionality can be extended with these optional plugins.

##### Embree Rendering

This component contains an example rendering backend for Hydra and usdview, based on the
embree raycasting library. Enable the plugin in the build by specifying the cmake flag
```PXR_BUILD_EMBREE_PLUGIN=TRUE``` when invoking cmake. This plugin is compatible with
Embree 2.16.1. The additional dependencies that must be supplied when invoking cmake are:

| Dependency Name       | Description                                 | Version   |
| --------------        | -----------------------------------         | -------   |
| EMBREE_LOCATION       | The root path to an embree library install. | 2.16.1    |

## Third Party Plugins

USD provides several plugins for integration with third-party software packages,
including Maya, Katana, Houdini, and Alembic. There is additional documentation on each plugin 
[here](http://openusd.org/docs/USD-3rd-Party-Plugins.html).
These plugins are not built by default and must be enabled via the instructions below.

##### Alembic Plugin

Enable the [Alembic](https://github.com/alembic/alembic) plugin in the build
by specifying the cmake flag ```PXR_BUILD_ALEMBIC_PLUGIN=TRUE``` when invoking cmake.
This plugin is compatible with Alembic 1.5.2. The additional dependencies that must be supplied when invoking cmake are:

| Dependency Name    | Description                                                             | Version |
| ------------------ |-----------------------------------------------------------------------  | ------- |
| ALEMBIC_LOCATION   | The location of [Alembic](https://https://github.com/alembic/alembic)   | 1.5.2   |
| OPENEXR_LOCATION   | The location of [OpenEXR](http://www.openexr.com)                       | 2.2.0   |

Support for Alembic files using the HDF5 backend is enabled by default but can be
disabled by specifying the cmake flag ```PXR_ENABLE_HDF5_SUPPORT=FALSE```. HDF5
support requires the following dependencies:

| Dependency Name    | Description                                                             | Version |
| ------------------ |-----------------------------------------------------------------------  | ------- |
| HDF5_LOCATION      | The location of [HDF5](https://www.hdfgroup.org/HDF5/)                  | 1.8.11  |

For further information see the documentation on the Alembic plugin [here](http://openusd.org/docs/Alembic-USD-Plugin.html).

##### Maya Plugin

Enable the Maya plugin in the build by specifying the cmake flag ```PXR_BUILD_MAYA_PLUGIN=TRUE``` 
when invoking cmake. This plugin is compatible with Maya 2016. The additional dependencies that must be supplied when invoking cmake are:

| Dependency Name   | Description                                                                                     | Version   |
| ----------------- | -----------------------------------                                                             | --------- |
| MAYA_LOCATION     | The root path to a Maya SDK install                                                             | Maya 2016 EXT2 SP2 |
| MAYA_tbb_LIBRARY  | The location of TBB, this should be the same as TBB_tbb_LIBRARY provided to the core USD build  |           |

For further information see the documentation on the Maya plugin [here](http://openusd.org/docs/Maya-USD-Plugins.html).

##### Katana Plugin

Enable the Katana plugin in the build by specifying the cmake flag ```PXR_BUILD_KATANA_PLUGIN=TRUE``` 
when invoking cmake. This plugin is compatible with Katana 2.0v5. The additional dependencies that must be supplied when invoking cmake are:

| Dependency Name       | Description                           | Version   |
| --------------        | -----------------------------------   | -------   |
| KATANA_API_LOCATION   | The root path to a Katana SDK install.| 2.0v5     |

For further information see our additional documentation on the Katana plugins [here](http://openusd.org/docs/Katana-USD-Plugins.html).

##### Houdini Plugin

Enable the Houdini plugin in the build by specifying the cmake flag ```PXR_BUILD_HOUDINI_PLUGIN=TRUE``` 
when invoking cmake. This plugin is compatible with Houdini 16.0. The additional dependencies that must be supplied when invoking cmake are:

| Dependency Name       | Description                            | Version   |
| --------------        | -----------------------------------    | -------   |
| HOUDINI_ROOT          | The root path to a Houdini SDK install.| 16.0      |

For further information see our additional documentation on the Houdini plugins [here](http://openusd.org/docs/Houdini-USD-Plugins.html).

## Tests

Disable unit testing and prevent tests from being built by specifying the cmake flag ```PXR_BUILD_TESTS=FALSE``` 
when invoking cmake.

## Other Build Options

##### Plugin Metadata Location

Each library in the USD core generally has an associated file named 'plugInfo.json' that contains metadata about that library,
such as the schema types provided by that library. These files are consumed by USD's internal plugin system to lazily load
libraries when needed. 

The plugin system requires knowledge of where these metadata files are located. The cmake build will ensure this is set up
properly based on the install location of the build. However, if you plan to relocate these files to a new location after
the build, you must inform the build by setting the cmake variable ```PXR_INSTALL_LOCATION``` to the intended final
directory where these files will be located. This variable may be a ':'-delimited list of paths.

##### Shared library prefix

By default shared libraries will have the prefix 'lib'. This means, for a given
component such as [usdGeom](pxr/usd/lib/usdGeom), the build will generate a corresponding 
libusdGeom object (libusdGeom.so on Linux, libusdGeom.dll on Windows 
and libusdGeom.dylib on Mac). You can change the prefix (or remove it) through 
```PXR_LIB_PREFIX```. For example,

```
-DPXR_LIB_PREFIX=pxr
```

Will generate pxrusdGeom.so on Linux, pxrusdGeom.dll on Windows and 
pxrusdGeom.dylib on Mac for the usdGeom component.

> Note: This prefix does not apply to shared objects used for Python bindings.

## USD Developer Options

##### C++ Namespace Configuration

USD comes with options to enable and customize C++ namespaces via the following
flags:

| Option Name                    | Description                             | Default |
| ------------------------------ |-----------------------------------------| ------- |
| PXR_SET_EXTERNAL_NAMESPACE     | The outer namespace identifier          | ```pxr```     |
| PXR_SET_INTERNAL_NAMESPACE     | The internal namespace identifier       | ```pxrInternal_v_x_y``` (for version x.y.z) |
| PXR_ENABLE_NAMESPACES          | Enable namespaces                       | ```OFF```    |

When enabled, there are a set of macros provided in a generated header, 
pxr/pxr.h, which facilitates using namespaces:

| Macro Name                     | Description                             | 
| ------------------------------ |-----------------------------------------| 
| PXR_NAMESPACE_OPEN_SCOPE       | Opens the namespace scope.                                           |
| PXR_NAMESPACE_CLOSE_SCOPE      | Closes the namespace.                                                |
| PXR_NS                         | Explicit qualification on items, e.g. ```PXR_NS::TfToken foo = ...```|
| PXR_NAMESPACE_USING_DIRECTIVE  | Enacts a using-directive, e.g. ```using namespace PXR_NS;```         |

##### ASCII Parser Editing/Validation

There is an ASCII parser for the USD file format, which can be found in 
[sdf](pxr/usd/lib/sdf/). Most users will not have a need to edit the parser, but 
for the adventurous ones, there are a couple additional requirements.

If you choose to edit the ASCII parsers, make sure 
```PXR_VALIDATE_GENERATED_CODE``` is set to ```TRUE```.  This flag enables tests 
that check the generated code in [sdf](pxr/usd/lib/sdf) and 
[gf](pxr/base/lib/gf).

| Dependency Name                | Description                                                      | Version |
| ------------------------------ |----------------------------------------------------------------- | ------- |
| FLEX_EXECUTABLE                | Path to [flex](http://flex.sourceforge.net/) executable          | 2.5.35  |
| BISON_EXECUTABLE               | Path to [bison](https://www.gnu.org/software/bison/) executable  | 2.4.1   |                        

##### USD Schema Generation

USD generates some code through a process called [schema 
generation]. This process requires the following python modules be installed
and available on the syspath. You can learn more about Schemas and why you 
might want to generate them
[here](http://openusd.org//docs/Generating-New-Schema-Classes.html).

| Python Module Name                                           | Description                                                      | Version |
| ------------------------------------------------------------ |----------------------------------------------------------------- | ------- |
| [Jinja2](http://jinja.pocoo.org/docs/dev/)                   | Jinja is the core code generator of usdGenSchema                 | 2.0     |
| [Argparse](https://docs.python.org/3/library/argparse.html)  | Argparse is used for basic command line arguments                |         |


## Optimization Options

There are certain optimizations that can be enabled in the build.

##### Malloc Library

We've found that USD performs best with allocators such as [Jemalloc](https://github.com/jemalloc/jemalloc).
In support of this, you can specify your own allocator through ```PXR_MALLOC_LIBRARY```.
This variable should be set to a path to a shared object for the allocator. For example,

```bash
-DPXR_MALLOC_LIBRARY:path=/usr/local/lib/libjemalloc.so
```

If none are specified, the default allocator will be used. More information on getting the most out of
USD can be found [Getting the Best Performance with USD](http://openusd.org/docs/Maximizing-USD-Performance.html).

## Linker Options

There are four ways to link USD controlled by the following options:

| Option Name            | Default   | Description                               |
| ---------------------- | --------- | ----------------------------------------- |
| BUILD_SHARED_LIBS      | ```ON```  | Build shared or static libraries          |
| PXR_BUILD_MONOLITHIC   | ```OFF``` | Build single or several libraries         |
| PXR_MONOLITHIC_IMPORT  |           | CMake file defining usd_ms import library |

##### Shared Libraries

The default creates several shared libraries.  This option allows loading
just the libraries necessary for a given task.

| Option Name            | Value     |
| ---------------------- | --------- |
| BUILD_SHARED_LIBS      | ```ON```  |
| PXR_BUILD_MONOLITHIC   | ```OFF``` |
| PXR_MONOLITHIC_IMPORT  |           |

```bash
cmake -DBUILD_SHARED_LIBS=ON ...
```

##### Static Libraries

This mode builds several static libraries.  This option allows embedding
just the libraries necessary for a given task.  However, it does not allow
USD plugins or Python modules since that would necessarily cause multiple
symbol definitions;  for any given symbol we'd have an instance in the main
application and another in each plugin/module.

| Option Name            | Value     |
| ---------------------- | --------- |
| BUILD_SHARED_LIBS      | ```OFF``` |
| PXR_BUILD_MONOLITHIC   | ```OFF``` |
| PXR_MONOLITHIC_IMPORT  |           |

```bash
cmake -DBUILD_SHARED_LIBS=OFF ...
```

##### Internal Monolithic Library

This mode builds the core libraries (i.e. everything under `pxr/`) into a
single archive library, 'usd_m', and from that it builds a single shared
library, 'usd_ms'.  It builds plugins outside of `pxr/` and Python modules
as usual except they link against 'usd_ms' instead of the individual
libraries of the default mode.  Plugins inside of `pxr/` are compiled into
'usd_m' and 'usd_ms'.  plugInfo.json files under `pxr/` refer to 'usd_ms'.

This mode is useful to reduce the number of installed files and simplify
linking against USD.

| Option Name            | Value      |
| ---------------------- | ---------- |
| BUILD_SHARED_LIBS      | _Don't care_ |
| PXR_BUILD_MONOLITHIC   | ```ON```   |
| PXR_MONOLITHIC_IMPORT  |            |

```bash
cmake -DPXR_BUILD_MONOLITHIC=ON ...
```

##### External Monolithic Library

This mode is similar to the
[Internal Monolithic Library](#internal-monolithic-library) except the
client has control of building the monolithic shared library.  This mode
is useful to embed USD into another shared library.  The build steps are
significantly more complicated and are described below.

| Option Name            | Value      |
| ---------------------- | ---------- |
| BUILD_SHARED_LIBS      | _Don't care_ |
| PXR_BUILD_MONOLITHIC   | ```ON```   |
| PXR_MONOLITHIC_IMPORT  | _Path-to-import-file_ |

To build in this mode:

1. Choose a path where the import file will be.  You'll be creating a cmake
file with `add_library(usd_ms SHARED IMPORTED)` and one or more `set_property`
calls.  The file doesn't need to exist.  If it does exist it should be empty
or valid cmake code.
1. Configure the build in the usual way but with `PXR_BUILD_MONOLITHIC=ON`
and `PXR_MONOLITHIC_IMPORT` set to the path in step 1.
1. Build the usual way except the target is `monolithic`.
1. Create your shared library. If using cmake you can include the file
`pxr/usd-targets-<CONFIG>` under the USD binary (build) directory, where
`<CONFIG>` is the configuration you built in step 3. Then you can link your
library against 'usd_m'.  However, this isn't as simple as
`target_link_libraries(mylib PUBLIC usd_m)` because you must get
**everything** from 'usd_m'.  See [Linking Whole Archives](#linking-whole-archives)
for more details.
1. Edit the import file to describe your library.  Your cmake build may
be able to generate the file directly via `export()`.  The USD build
will include this file and having done so must be able to link against
your library by adding 'usd_ms' as a target link library.  The file
should look something like this:
    ```cmake
    add_library(usd_ms SHARED IMPORTED)
    set_property(TARGET usd_ms PROPERTY IMPORTED_LOCATION ...)
    # The following is necessary on Windows.
    #set_property(TARGET usd_ms PROPERTY IMPORTED_IMPLIB ...)
    set_property(TARGET usd_ms PROPERTY INTERFACE_COMPILE_DEFINITIONS ...)
    set_property(TARGET usd_ms PROPERTY INTERFACE_INCLUDE_DIRECTORIES ...)
    set_property(TARGET usd_ms PROPERTY INTERFACE_LINK_LIBRARIES ...)
    ```
1. Complete the USD build by building the usual way, either with the
default target or the 'install' target.

Two notes:
1. Your library does **not** need to be named usd_ms. That's simply the
name given to it by the import file. The IMPORTED_LOCATION  has the real
name and path to your library.
1. USD currently only supports installations where your library is in
the same directory the USD library/libraries would have been relative
to the other installed USD files.  Specifically, the location of your
library will be used to find plugInfo.json files using the relative
paths `../share/usd/plugins` and `../plugin/usd`.

###### Linking Whole Archives

Normally when linking against a static library the linker will only pull
in object files that provide a needed symbol. USD has many files that
have static global objects with constructors with side effects.  If
nothing uses any visible symbol from those object files then a normal
link would not include them. The side effects will not occur and USD
will not work.

To include everything you need to tell the linker to include the whole
archive.  That's platform dependent and you'll want code something like
this:

```cmake
if(MSVC)
    target_link_libraries(mylib -WHOLEARCHIVE:$<TARGET_FILE:usd_m> usd_m)
elseif(CMAKE_COMPILER_IS_GNUCXX)
    target_link_libraries(mylib -Wl,--whole-archive usd_m -Wl,--no-whole-archive)
elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
    target_link_libraries(mylib -Wl,-force_load usd_m)
endif()
```

On Windows cmake cannot recognize 'usd_m' as a library when appended to
 -WHOLEARCHIVE: because it's not a word to itself so we use TARGET_FILE
to get the path to the library. We also link 'usd_m' separately so cmake
will add usd_m's interface link libraries, etc. This second instance
doesn't increase the resulting file size because all symbols will be
found in the first (-WHOLEARCHIVE) instance.
