1#
2# Copyright 2016 Pixar
3#
4# Licensed under the Apache License, Version 2.0 (the "Apache License")
5# with the following modification; you may not use this file except in
6# compliance with the Apache License and the following modification to it:
7# Section 6. Trademarks. is deleted and replaced with:
8#
9# 6. Trademarks. This License does not grant permission to use the trade
10#    names, trademarks, service marks, or product names of the Licensor
11#    and its affiliates, except as required to comply with Section 4(c) of
12#    the License and to reproduce the content of the NOTICE file.
13#
14# You may obtain a copy of the Apache License at
15#
16#     http://www.apache.org/licenses/LICENSE-2.0
17#
18# Unless required by applicable law or agreed to in writing, software
19# distributed under the Apache License with the above modification is
20# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21# KIND, either express or implied. See the Apache License for the specific
22# language governing permissions and limitations under the Apache License.
23#
24include(Private)
25
26function(pxr_build_documentation)
27    configure_file(${CMAKE_SOURCE_DIR}/docs/doxygen/Doxyfile.in
28                   ${CMAKE_BINARY_DIR}/Doxyfile)
29
30    add_custom_target(
31        documentation
32        ALL
33        # We need to manually copy pxr.h into the docs/include directory
34        # since it's generated outside of the libraries.
35        COMMAND
36            ${CMAKE_COMMAND} -E copy
37            "${CMAKE_BINARY_DIR}/include/pxr/pxr.h"
38            "${CMAKE_BINARY_DIR}/docs/include/pxr/pxr.h"
39        COMMAND
40            ${CMAKE_COMMAND} -E copy_directory
41            "${CMAKE_SOURCE_DIR}/docs"
42            "${CMAKE_BINARY_DIR}/docs"
43    )
44
45    # Execute doxygen during the install step. All of the files we want
46    # doxygen to process should already have been copied to the docs
47    # directory during the build step
48    install(CODE "execute_process(COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_BINARY_DIR}/Doxyfile)")
49
50    set(INST_DOCS_ROOT  "${CMAKE_INSTALL_PREFIX}/docs")
51
52    set(BUILT_HTML_DOCS "${CMAKE_BINARY_DIR}/docs/doxy_html")
53    install(
54        DIRECTORY ${BUILT_HTML_DOCS}
55        DESTINATION ${INST_DOCS_ROOT}
56    )
57
58    set(BUILT_XML_DOCS "${CMAKE_BINARY_DIR}/docs/doxy_xml")
59    install(
60        DIRECTORY ${BUILT_XML_DOCS}
61        DESTINATION ${INST_DOCS_ROOT}
62    )
63endfunction()
64
65function(pxr_python_bin BIN_NAME)
66    set(oneValueArgs
67        PYTHON_FILE
68    )
69    set(multiValueArgs
70        DEPENDENCIES
71    )
72    cmake_parse_arguments(pb
73        ""
74        "${oneValueArgs}"
75        "${multiValueArgs}"
76        ${ARGN}
77    )
78
79    # If we can't build Python modules then do nothing.
80    if(NOT TARGET python)
81        message(STATUS "Skipping Python program ${BIN_NAME}, Python modules required")
82        return()
83    endif()
84
85    _get_install_dir(bin installDir)
86
87    # Source file.
88    if( "${pb_PYTHON_FILE}" STREQUAL "")
89        set(infile ${CMAKE_CURRENT_SOURCE_DIR}/${BIN_NAME}.py)
90    else()
91        set(infile ${CMAKE_CURRENT_SOURCE_DIR}/${pb_PYTHON_FILE})
92    endif()
93
94    # Destination file.
95    set(outfile ${CMAKE_CURRENT_BINARY_DIR}/${BIN_NAME})
96
97    # /pxrpythonsubst will be replaced with the full path to the configured
98    # python executable. This doesn't use the CMake ${...} or @...@ syntax
99    # for backwards compatibility with other build systems.
100    add_custom_command(
101        OUTPUT ${outfile}
102        DEPENDS ${infile}
103        COMMENT "Substituting Python shebang"
104        COMMAND
105            ${PYTHON_EXECUTABLE}
106            ${PROJECT_SOURCE_DIR}/cmake/macros/shebang.py
107            ${PXR_PYTHON_SHEBANG}
108            ${infile}
109            ${outfile}
110    )
111    list(APPEND outputs ${outfile})
112
113    install(
114        PROGRAMS ${outfile}
115        DESTINATION ${installDir}
116        RENAME ${BIN_NAME}
117    )
118
119    # Windows by default cannot execute Python files so here
120    # we create a batch file wrapper that invokes the python
121    # files.
122    if(WIN32)
123        add_custom_command(
124            OUTPUT ${outfile}.cmd
125            COMMENT "Creating Python cmd wrapper"
126            COMMAND
127                ${PYTHON_EXECUTABLE}
128                ${PROJECT_SOURCE_DIR}/cmake/macros/shebang.py
129                ${BIN_NAME}
130                ${outfile}.cmd
131        )
132        list(APPEND outputs ${outfile}.cmd)
133
134        install(
135            PROGRAMS ${outfile}.cmd
136            DESTINATION ${installDir}
137            RENAME ${BIN_NAME}.cmd
138        )
139    endif()
140
141    # Add the target.
142    add_custom_target(${BIN_NAME}_script
143        DEPENDS ${outputs} ${pb_DEPENDENCIES}
144    )
145    add_dependencies(python ${BIN_NAME}_script)
146
147    _get_folder("" folder)
148    set_target_properties(${BIN_NAME}_script
149        PROPERTIES
150            FOLDER "${folder}"
151    )
152endfunction() # pxr_python_bin
153
154function(pxr_cpp_bin BIN_NAME)
155    _get_install_dir(bin installDir)
156
157    set(multiValueArgs
158        LIBRARIES
159        INCLUDE_DIRS
160    )
161
162    cmake_parse_arguments(cb
163        ""
164        ""
165        "${multiValueArgs}"
166        ${ARGN}
167    )
168
169    add_executable(${BIN_NAME} ${BIN_NAME}.cpp)
170
171    # Turn PIC ON otherwise ArchGetAddressInfo() on Linux may yield
172    # unexpected results.
173    _get_folder("" folder)
174    set_target_properties(${BIN_NAME}
175        PROPERTIES
176            FOLDER "${folder}"
177            POSITION_INDEPENDENT_CODE ON
178    )
179
180    # Install and include headers from the build directory.
181    get_filename_component(
182        PRIVATE_INC_DIR
183        "${CMAKE_BINARY_DIR}/include"
184        ABSOLUTE
185    )
186
187    target_include_directories(${BIN_NAME}
188        PRIVATE
189        ${PRIVATE_INC_DIR}
190        ${cb_INCLUDE_DIRS}
191    )
192
193    _pxr_init_rpath(rpath "${installDir}")
194    _pxr_install_rpath(rpath ${BIN_NAME})
195
196    _pxr_target_link_libraries(${BIN_NAME}
197        ${cb_LIBRARIES}
198        ${PXR_MALLOC_LIBRARY}
199    )
200
201    install(
202        TARGETS ${BIN_NAME}
203        DESTINATION ${installDir}
204    )
205endfunction()
206
207function(pxr_library NAME)
208    set(options
209        DISABLE_PRECOMPILED_HEADERS
210    )
211    set(oneValueArgs
212        TYPE
213        PRECOMPILED_HEADER_NAME
214    )
215    set(multiValueArgs
216        PUBLIC_CLASSES
217        PUBLIC_HEADERS
218        PRIVATE_CLASSES
219        PRIVATE_HEADERS
220        CPPFILES
221        LIBRARIES
222        INCLUDE_DIRS
223        DOXYGEN_FILES
224        RESOURCE_FILES
225        PYTHON_PUBLIC_CLASSES
226        PYTHON_PRIVATE_CLASSES
227        PYTHON_PUBLIC_HEADERS
228        PYTHON_PRIVATE_HEADERS
229        PYTHON_CPPFILES
230        PYMODULE_CPPFILES
231        PYMODULE_FILES
232        PYSIDE_UI_FILES
233    )
234
235    cmake_parse_arguments(args
236        "${options}"
237        "${oneValueArgs}"
238        "${multiValueArgs}"
239        ${ARGN}
240    )
241
242    # If python support is enabled, merge the python specific categories
243    # with the more general before setting up compilation.
244    if(PXR_ENABLE_PYTHON_SUPPORT)
245        if(args_PYTHON_PUBLIC_CLASSES)
246            list(APPEND args_PUBLIC_CLASSES ${args_PYTHON_PUBLIC_CLASSES})
247        endif()
248        if(args_PYTHON_PUBLIC_HEADERS)
249            list(APPEND args_PUBLIC_HEADERS ${args_PYTHON_PUBLIC_HEADERS})
250        endif()
251        if(args_PYTHON_PRIVATE_CLASSES)
252            list(APPEND args_PRIVATE_CLASSES ${args_PYTHON_PRIVATE_CLASSES})
253        endif()
254        if(args_PYTHON_PRIVATE_HEADERS)
255            list(APPEND args_PRIVATE_HEADERS ${args_PYTHON_PRIVATE_HEADERS})
256        endif()
257        if(args_PYTHON_CPPFILES)
258            list(APPEND args_CPPFILES ${args_PYTHON_CPPFILES})
259        endif()
260    endif()
261
262    # Collect libraries.
263    if(NOT args_TYPE STREQUAL "PLUGIN")
264        get_property(help CACHE PXR_ALL_LIBS PROPERTY HELPSTRING)
265        list(APPEND PXR_ALL_LIBS ${NAME})
266        set(PXR_ALL_LIBS "${PXR_ALL_LIBS}" CACHE INTERNAL "${help}")
267        if(args_TYPE STREQUAL "STATIC")
268            # Note if this library is explicitly STATIC.
269            get_property(help CACHE PXR_STATIC_LIBS PROPERTY HELPSTRING)
270            list(APPEND PXR_STATIC_LIBS ${NAME})
271            set(PXR_STATIC_LIBS "${PXR_STATIC_LIBS}" CACHE INTERNAL "${help}")
272        endif()
273    endif()
274
275    # Expand classes into filenames.
276    _classes(${NAME} ${args_PRIVATE_CLASSES} PRIVATE)
277    _classes(${NAME} ${args_PUBLIC_CLASSES} PUBLIC)
278
279    # If building a core plugin for a monolithic build then treat it almost
280    # like any other library and include it in the monolithic library.
281    if (_building_core AND _building_monolithic AND args_TYPE STREQUAL "PLUGIN")
282        set(args_TYPE "OBJECT_PLUGIN")
283    endif()
284
285    # Custom tweaks.
286    if(args_TYPE STREQUAL "PLUGIN")
287        # We can't build plugins if we're not building shared libraries.
288        if(NOT TARGET shared_libs)
289            message(STATUS "Skipping plugin ${NAME}, shared libraries required")
290            return()
291        endif()
292
293        set(prefix "")
294        set(suffix ${CMAKE_SHARED_LIBRARY_SUFFIX})
295    else()
296        # If the caller didn't specify the library type then choose the
297        # type now.
298        if("x${args_TYPE}" STREQUAL "x")
299            if(_building_monolithic)
300                set(args_TYPE "OBJECT")
301            elseif(BUILD_SHARED_LIBS)
302                set(args_TYPE "SHARED")
303            else()
304                set(args_TYPE "STATIC")
305            endif()
306        endif()
307
308        set(prefix "${PXR_LIB_PREFIX}")
309        if(args_TYPE STREQUAL "STATIC")
310            set(suffix ${CMAKE_STATIC_LIBRARY_SUFFIX})
311        else()
312            set(suffix ${CMAKE_SHARED_LIBRARY_SUFFIX})
313        endif()
314    endif()
315
316    set(pch "ON")
317    if(args_DISABLE_PRECOMPILED_HEADERS)
318        set(pch "OFF")
319    endif()
320
321    _pxr_library(${NAME}
322        TYPE "${args_TYPE}"
323        PREFIX "${prefix}"
324        SUFFIX "${suffix}"
325        SUBDIR "${subdir}"
326        CPPFILES "${args_CPPFILES};${${NAME}_CPPFILES}"
327        PUBLIC_HEADERS "${args_PUBLIC_HEADERS};${${NAME}_PUBLIC_HEADERS}"
328        PRIVATE_HEADERS "${args_PRIVATE_HEADERS};${${NAME}_PRIVATE_HEADERS}"
329        LIBRARIES "${args_LIBRARIES}"
330        INCLUDE_DIRS "${args_INCLUDE_DIRS}"
331        RESOURCE_FILES "${args_RESOURCE_FILES}"
332        DOXYGEN_FILES "${args_DOXYGEN_FILES}"
333        PRECOMPILED_HEADERS "${pch}"
334        PRECOMPILED_HEADER_NAME "${args_PRECOMPILED_HEADER_NAME}"
335        LIB_INSTALL_PREFIX_RESULT libInstallPrefix
336    )
337
338    if(PXR_ENABLE_PYTHON_SUPPORT AND (args_PYMODULE_CPPFILES OR args_PYMODULE_FILES OR args_PYSIDE_UI_FILES))
339        _pxr_python_module(
340            ${NAME}
341            WRAPPED_LIB_INSTALL_PREFIX "${libInstallPrefix}"
342            PYTHON_FILES ${args_PYMODULE_FILES}
343            PYSIDE_UI_FILES ${args_PYSIDE_UI_FILES}
344            CPPFILES ${args_PYMODULE_CPPFILES}
345            INCLUDE_DIRS ${args_INCLUDE_DIRS}
346            PRECOMPILED_HEADERS ${pch}
347            PRECOMPILED_HEADER_NAME ${args_PRECOMPILED_HEADER_NAME}
348        )
349    endif()
350endfunction()
351
352macro(pxr_shared_library NAME)
353    pxr_library(${NAME} TYPE "SHARED" ${ARGN})
354endmacro(pxr_shared_library)
355
356macro(pxr_static_library NAME)
357    pxr_library(${NAME} TYPE "STATIC" ${ARGN})
358endmacro(pxr_static_library)
359
360macro(pxr_plugin NAME)
361    pxr_library(${NAME} TYPE "PLUGIN" ${ARGN})
362endmacro(pxr_plugin)
363
364function(pxr_setup_python)
365    get_property(pxrPythonModules GLOBAL PROPERTY PXR_PYTHON_MODULES)
366
367    # A new list where each python module is quoted
368    set(converted "")
369    foreach(module ${pxrPythonModules})
370        list(APPEND converted "'${module}'")
371    endforeach()
372
373    # Join these with a ', '
374    string(REPLACE ";" ", " pyModulesStr "${converted}")
375
376    # Install a pxr __init__.py with an appropriate __all__
377    _get_install_dir(lib/python/pxr installPrefix)
378
379    file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/generated_modules_init.py"
380         "__all__ = [${pyModulesStr}]\n")
381
382    install(
383        FILES "${CMAKE_CURRENT_BINARY_DIR}/generated_modules_init.py"
384        DESTINATION ${installPrefix}
385        RENAME "__init__.py"
386    )
387endfunction() # pxr_setup_python
388
389function (pxr_create_test_module MODULE_NAME)
390    # If we can't build Python modules then do nothing.
391    if(NOT TARGET python)
392        return()
393    endif()
394
395    if (NOT PXR_BUILD_TESTS)
396        return()
397    endif()
398
399    # If the package for this test does not have a target it must not be
400    # getting built, in which case we can skip building associated tests.
401    if (NOT TARGET ${PXR_PACKAGE})
402        return()
403    endif()
404
405    cmake_parse_arguments(tm "" "INSTALL_PREFIX;SOURCE_DIR" "" ${ARGN})
406
407    if (NOT tm_SOURCE_DIR)
408        set(tm_SOURCE_DIR testenv)
409    endif()
410
411    # Look specifically for an __init__.py and a plugInfo.json prefixed by the
412    # module name. These will be installed without the module prefix.
413    set(initPyFile ${tm_SOURCE_DIR}/${MODULE_NAME}__init__.py)
414    set(plugInfoFile ${tm_SOURCE_DIR}/${MODULE_NAME}_plugInfo.json)
415
416    # XXX -- We shouldn't have to install to run tests.
417    if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${initPyFile}")
418        install(
419            FILES
420                ${initPyFile}
421            RENAME
422                __init__.py
423            DESTINATION
424                tests/${tm_INSTALL_PREFIX}/lib/python/${MODULE_NAME}
425        )
426    endif()
427    if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${plugInfoFile}")
428        install(
429            FILES
430                ${plugInfoFile}
431            RENAME
432                plugInfo.json
433            DESTINATION
434                tests/${tm_INSTALL_PREFIX}/lib/python/${MODULE_NAME}
435        )
436    endif()
437endfunction() # pxr_create_test_module
438
439function(pxr_build_test_shared_lib LIBRARY_NAME)
440    if (NOT PXR_BUILD_TESTS)
441        return()
442    endif()
443
444    # If the package for this test does not have a target it must not be
445    # getting built, in which case we can skip building associated tests.
446    if (NOT TARGET ${PXR_PACKAGE})
447        return()
448    endif()
449
450    cmake_parse_arguments(bt
451        ""
452        "INSTALL_PREFIX;SOURCE_DIR"
453        "LIBRARIES;CPPFILES"
454        ${ARGN}
455    )
456
457    add_library(${LIBRARY_NAME}
458        SHARED
459        ${bt_CPPFILES}
460    )
461    _pxr_target_link_libraries(${LIBRARY_NAME}
462        ${bt_LIBRARIES}
463    )
464    _get_folder("tests/lib" folder)
465    set_target_properties(${LIBRARY_NAME}
466        PROPERTIES
467            FOLDER "${folder}"
468    )
469
470    # Find libraries under the install prefix, which has the core USD
471    # libraries.
472    _pxr_init_rpath(rpath "tests/lib")
473    _pxr_add_rpath(rpath "${CMAKE_INSTALL_PREFIX}/lib")
474    _pxr_install_rpath(rpath ${LIBRARY_NAME})
475
476    if (NOT bt_SOURCE_DIR)
477        set(bt_SOURCE_DIR testenv)
478    endif()
479    set(testPlugInfoSrcPath ${bt_SOURCE_DIR}/${LIBRARY_NAME}_plugInfo.json)
480
481    if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${testPlugInfoSrcPath}")
482        set(TEST_PLUG_INFO_RESOURCE_PATH "Resources")
483        set(TEST_PLUG_INFO_ROOT "..")
484        set(LIBRARY_FILE "${CMAKE_SHARED_LIBRARY_PREFIX}${LIBRARY_NAME}${CMAKE_SHARED_LIBRARY_SUFFIX}")
485
486        set(testPlugInfoLibDir "tests/${bt_INSTALL_PREFIX}/lib/${LIBRARY_NAME}")
487        set(testPlugInfoResourceDir "${testPlugInfoLibDir}/${TEST_PLUG_INFO_RESOURCE_PATH}")
488        set(testPlugInfoPath "${CMAKE_BINARY_DIR}/${testPlugInfoResourceDir}/plugInfo.json")
489
490        file(RELATIVE_PATH
491            TEST_PLUG_INFO_LIBRARY_PATH
492            "${CMAKE_INSTALL_PREFIX}/${testPlugInfoLibDir}"
493            "${CMAKE_INSTALL_PREFIX}/tests/lib/${LIBRARY_FILE}")
494
495        configure_file("${testPlugInfoSrcPath}" "${testPlugInfoPath}")
496        # XXX -- We shouldn't have to install to run tests.
497        install(
498            FILES ${testPlugInfoPath}
499            DESTINATION ${testPlugInfoResourceDir})
500    endif()
501
502    # We always want this test to build after the package it's under, even if
503    # it doesn't link directly. This ensures that this test is able to include
504    # headers from its parent package.
505    add_dependencies(${LIBRARY_NAME} ${PXR_PACKAGE})
506
507    # Test libraries can include the private headers of their parent PXR_PACKAGE
508    # library
509    target_include_directories(${LIBRARY_NAME}
510        PRIVATE $<TARGET_PROPERTY:${PXR_PACKAGE},INCLUDE_DIRECTORIES>
511    )
512
513    # XXX -- We shouldn't have to install to run tests.
514    install(
515        TARGETS ${LIBRARY_NAME}
516        LIBRARY DESTINATION "tests/lib"
517        ARCHIVE DESTINATION "tests/lib"
518        RUNTIME DESTINATION "tests/lib"
519    )
520endfunction() # pxr_build_test_shared_lib
521
522function(pxr_build_test TEST_NAME)
523    if (NOT PXR_BUILD_TESTS)
524        return()
525    endif()
526
527    # If the package for this test does not have a target it must not be
528    # getting built, in which case we can skip building associated tests.
529    if (NOT TARGET ${PXR_PACKAGE})
530        return()
531    endif()
532
533    cmake_parse_arguments(bt
534        "" ""
535        "LIBRARIES;CPPFILES"
536        ${ARGN}
537    )
538
539    add_executable(${TEST_NAME}
540        ${bt_CPPFILES}
541    )
542
543    # Turn PIC ON otherwise ArchGetAddressInfo() on Linux may yield
544    # unexpected results.
545    _get_folder("tests/bin" folder)
546    set_target_properties(${TEST_NAME}
547        PROPERTIES
548            FOLDER "${folder}"
549        	POSITION_INDEPENDENT_CODE ON
550    )
551    target_include_directories(${TEST_NAME}
552        PRIVATE $<TARGET_PROPERTY:${PXR_PACKAGE},INCLUDE_DIRECTORIES>
553    )
554    _pxr_target_link_libraries(${TEST_NAME}
555        ${bt_LIBRARIES}
556    )
557
558    # Find libraries under the install prefix, which has the core USD
559    # libraries.
560    _pxr_init_rpath(rpath "tests")
561    _pxr_add_rpath(rpath "${CMAKE_INSTALL_PREFIX}/lib")
562    _pxr_install_rpath(rpath ${TEST_NAME})
563
564    # XXX -- We shouldn't have to install to run tests.
565    install(TARGETS ${TEST_NAME}
566        RUNTIME DESTINATION "tests"
567    )
568endfunction() # pxr_build_test
569
570function(pxr_test_scripts)
571    # If we can't build Python modules then do nothing.
572    if(NOT TARGET python)
573        return()
574    endif()
575
576    if (NOT PXR_BUILD_TESTS)
577        return()
578    endif()
579
580    # If the package for this test does not have a target it must not be
581    # getting built, in which case we can skip building associated tests.
582    if (NOT TARGET ${PXR_PACKAGE})
583        return()
584    endif()
585
586    foreach(file ${ARGN})
587        get_filename_component(destFile ${file} NAME_WE)
588        # XXX -- We shouldn't have to install to run tests.
589        install(
590            PROGRAMS ${file}
591            DESTINATION tests
592            RENAME ${destFile}
593        )
594    endforeach()
595endfunction() # pxr_test_scripts
596
597function(pxr_install_test_dir)
598    if (NOT PXR_BUILD_TESTS)
599        return()
600    endif()
601
602    # If the package for this test does not have a target it must not be
603    # getting built, in which case we can skip building associated tests.
604    if (NOT TARGET ${PXR_PACKAGE})
605        return()
606    endif()
607
608    cmake_parse_arguments(bt
609        ""
610        "SRC;DEST"
611        ""
612        ${ARGN}
613    )
614
615    # XXX -- We shouldn't have to install to run tests.
616    install(
617        DIRECTORY ${bt_SRC}/
618        DESTINATION tests/ctest/${bt_DEST}
619    )
620endfunction() # pxr_install_test_dir
621
622function(pxr_register_test TEST_NAME)
623    if (NOT PXR_BUILD_TESTS)
624        return()
625    endif()
626
627    # If the package for this test does not have a target it must not be
628    # getting built, in which case we can skip building associated tests.
629    if (NOT TARGET ${PXR_PACKAGE})
630        return()
631    endif()
632
633    cmake_parse_arguments(bt
634        "RUN_SERIAL;PYTHON;REQUIRES_SHARED_LIBS;REQUIRES_PYTHON_MODULES"
635        "CUSTOM_PYTHON;COMMAND;STDOUT_REDIRECT;STDERR_REDIRECT;POST_COMMAND;POST_COMMAND_STDOUT_REDIRECT;POST_COMMAND_STDERR_REDIRECT;PRE_COMMAND;PRE_COMMAND_STDOUT_REDIRECT;PRE_COMMAND_STDERR_REDIRECT;FILES_EXIST;FILES_DONT_EXIST;CLEAN_OUTPUT;EXPECTED_RETURN_CODE;TESTENV"
636        "DIFF_COMPARE;ENV;PRE_PATH;POST_PATH"
637        ${ARGN}
638    )
639
640    # Discard tests that required shared libraries.
641    if(NOT TARGET shared_libs)
642        # Explicit requirement.  This is for C++ tests that dynamically
643        # load libraries linked against USD code.  These tests will have
644        # multiple copies of symbols and will likely re-execute
645        # ARCH_CONSTRUCTOR and registration functions, which will almost
646        # certainly cause problems.
647        if(bt_REQUIRES_SHARED_LIBS)
648            message(STATUS "Skipping test ${TEST_NAME}, shared libraries required")
649            return()
650        endif()
651    endif()
652
653    if(NOT TARGET python)
654        # Implicit requirement.  Python modules require shared USD
655        # libraries.  If the test runs python it's certainly going
656        # to load USD modules.  If the test uses C++ to load USD
657        # modules it tells us via REQUIRES_PYTHON_MODULES.
658        if(bt_PYTHON OR bt_CUSTOM_PYTHON OR bt_REQUIRES_PYTHON_MODULES)
659            message(STATUS "Skipping test ${TEST_NAME}, Python modules required")
660            return()
661        endif()
662    endif()
663
664    # This harness is a filter which allows us to manipulate the test run,
665    # e.g. by changing the environment, changing the expected return code, etc.
666    set(testWrapperCmd ${PROJECT_SOURCE_DIR}/cmake/macros/testWrapper.py --verbose)
667
668    if (bt_STDOUT_REDIRECT)
669        set(testWrapperCmd ${testWrapperCmd} --stdout-redirect=${bt_STDOUT_REDIRECT})
670    endif()
671
672    if (bt_STDERR_REDIRECT)
673        set(testWrapperCmd ${testWrapperCmd} --stderr-redirect=${bt_STDERR_REDIRECT})
674    endif()
675
676    if (bt_PRE_COMMAND_STDOUT_REDIRECT)
677        set(testWrapperCmd ${testWrapperCmd} --pre-command-stdout-redirect=${bt_PRE_COMMAND_STDOUT_REDIRECT})
678    endif()
679
680    if (bt_PRE_COMMAND_STDERR_REDIRECT)
681        set(testWrapperCmd ${testWrapperCmd} --pre-command-stderr-redirect=${bt_PRE_COMMAND_STDERR_REDIRECT})
682    endif()
683
684    if (bt_POST_COMMAND_STDOUT_REDIRECT)
685        set(testWrapperCmd ${testWrapperCmd} --post-command-stdout-redirect=${bt_POST_COMMAND_STDOUT_REDIRECT})
686    endif()
687
688    if (bt_POST_COMMAND_STDERR_REDIRECT)
689        set(testWrapperCmd ${testWrapperCmd} --post-command-stderr-redirect=${bt_POST_COMMAND_STDERR_REDIRECT})
690    endif()
691
692    # Not all tests will have testenvs, but if they do let the wrapper know so
693    # it can copy the testenv contents into the run directory. By default,
694    # assume the testenv has the same name as the test but allow it to be
695    # overridden by specifying TESTENV.
696    if (bt_TESTENV)
697        set(testenvDir ${CMAKE_INSTALL_PREFIX}/tests/ctest/${bt_TESTENV})
698    else()
699        set(testenvDir ${CMAKE_INSTALL_PREFIX}/tests/ctest/${TEST_NAME})
700    endif()
701
702    set(testWrapperCmd ${testWrapperCmd} --testenv-dir=${testenvDir})
703
704    if (bt_DIFF_COMPARE)
705        foreach(compareFile ${bt_DIFF_COMPARE})
706            set(testWrapperCmd ${testWrapperCmd} --diff-compare=${compareFile})
707        endforeach()
708
709        # For now the baseline directory is assumed by convention from the test
710        # name. There may eventually be cases where we'd want to specify it by
711        # an argument though.
712        set(baselineDir ${testenvDir}/baseline)
713        set(testWrapperCmd ${testWrapperCmd} --baseline-dir=${baselineDir})
714    endif()
715
716    if (bt_CLEAN_OUTPUT)
717        set(testWrapperCmd ${testWrapperCmd} --clean-output-paths=${bt_CLEAN_OUTPUT})
718    endif()
719
720    if (bt_FILES_EXIST)
721        set(testWrapperCmd ${testWrapperCmd} --files-exist=${bt_FILES_EXIST})
722    endif()
723
724    if (bt_FILES_DONT_EXIST)
725        set(testWrapperCmd ${testWrapperCmd} --files-dont-exist=${bt_FILES_DONT_EXIST})
726    endif()
727
728    if (bt_PRE_COMMAND)
729        set(testWrapperCmd ${testWrapperCmd} --pre-command=${bt_PRE_COMMAND})
730    endif()
731
732    if (bt_POST_COMMAND)
733        set(testWrapperCmd ${testWrapperCmd} --post-command=${bt_POST_COMMAND})
734    endif()
735
736    if (bt_EXPECTED_RETURN_CODE)
737        set(testWrapperCmd ${testWrapperCmd} --expected-return-code=${bt_EXPECTED_RETURN_CODE})
738    endif()
739
740    if (bt_ENV)
741        foreach(env ${bt_ENV})
742            set(testWrapperCmd ${testWrapperCmd} --env-var=${env})
743        endforeach()
744    endif()
745
746    if (bt_PRE_PATH)
747        foreach(path ${bt_PRE_PATH})
748            set(testWrapperCmd ${testWrapperCmd} --pre-path=${path})
749        endforeach()
750    endif()
751
752    if (bt_POST_PATH)
753        foreach(path ${bt_POST_PATH})
754            set(testWrapperCmd ${testWrapperCmd} --post-path=${path})
755        endforeach()
756    endif()
757
758    # If we're building static libraries, the C++ tests that link against
759    # these libraries will look for resource files in the "usd" subdirectory
760    # relative to where the tests are installed. However, the build installs
761    # these files in the "lib" directory where the libraries are installed.
762    #
763    # We don't want to copy these resource files for each test, so instead
764    # we set the PXR_PLUGINPATH_NAME env var to point to the "lib/usd"
765    # directory where these files are installed.
766    if (NOT TARGET shared_libs)
767        set(testWrapperCmd ${testWrapperCmd} --env-var=${PXR_PLUGINPATH_NAME}=${CMAKE_INSTALL_PREFIX}/lib/usd)
768    endif()
769
770    # Ensure that Python imports the Python files built by this build.
771    # On Windows convert backslash to slash and don't change semicolons
772    # to colons.
773    set(_testPythonPath "${CMAKE_INSTALL_PREFIX}/lib/python;$ENV{PYTHONPATH}")
774    if(WIN32)
775        string(REGEX REPLACE "\\\\" "/" _testPythonPath "${_testPythonPath}")
776    else()
777        string(REPLACE ";" ":" _testPythonPath "${_testPythonPath}")
778    endif()
779
780    # Ensure we run with the appropriate python executable.
781    if (bt_CUSTOM_PYTHON)
782        set(testCmd "${bt_CUSTOM_PYTHON} ${bt_COMMAND}")
783    elseif (bt_PYTHON)
784        set(testCmd "${PYTHON_EXECUTABLE} ${bt_COMMAND}")
785    else()
786        set(testCmd "${bt_COMMAND}")
787    endif()
788
789    add_test(
790        NAME ${TEST_NAME}
791        COMMAND ${PYTHON_EXECUTABLE} ${testWrapperCmd}
792                "--env-var=PYTHONPATH=${_testPythonPath}" ${testCmd}
793    )
794
795    # But in some cases, we need to pass cmake properties directly to cmake
796    # run_test, rather than configuring the environment
797    if (bt_RUN_SERIAL)
798        set_tests_properties(${TEST_NAME} PROPERTIES RUN_SERIAL TRUE)
799    endif()
800
801endfunction() # pxr_register_test
802
803function(pxr_setup_plugins)
804    # Install a top-level plugInfo.json in the shared area and into the
805    # top-level plugin area
806    _get_resources_dir_name(resourcesDir)
807
808    # Add extra plugInfo.json include paths to the top-level plugInfo.json,
809    # relative to that top-level file.
810    set(extraIncludes "")
811    list(REMOVE_DUPLICATES PXR_EXTRA_PLUGINS)
812    foreach(dirName ${PXR_EXTRA_PLUGINS})
813        file(RELATIVE_PATH
814            relDirName
815            "${CMAKE_INSTALL_PREFIX}/lib/usd"
816            "${CMAKE_INSTALL_PREFIX}/${dirName}"
817        )
818        set(extraIncludes "${extraIncludes},\n        \"${relDirName}/\"")
819    endforeach()
820
821    set(plugInfoContents "{\n    \"Includes\": [\n        \"*/${resourcesDir}/\"${extraIncludes}\n    ]\n}\n")
822    file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/plugins_plugInfo.json"
823         "${plugInfoContents}")
824    install(
825        FILES "${CMAKE_CURRENT_BINARY_DIR}/plugins_plugInfo.json"
826        DESTINATION lib/usd
827        RENAME "plugInfo.json"
828    )
829
830    set(plugInfoContents "{\n    \"Includes\": [ \"*/${resourcesDir}/\" ]\n}\n")
831    file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/usd_plugInfo.json"
832         "${plugInfoContents}")
833    install(
834        FILES "${CMAKE_CURRENT_BINARY_DIR}/usd_plugInfo.json"
835        DESTINATION plugin/usd
836        RENAME "plugInfo.json"
837    )
838endfunction() # pxr_setup_plugins
839
840function(pxr_add_extra_plugins PLUGIN_AREAS)
841    # Install a top-level plugInfo.json in the given plugin areas.
842    _get_resources_dir_name(resourcesDir)
843    set(plugInfoContents "{\n    \"Includes\": [ \"*/${resourcesDir}/\" ]\n}\n")
844
845    get_property(help CACHE PXR_EXTRA_PLUGINS PROPERTY HELPSTRING)
846
847    foreach(area ${PLUGIN_AREAS})
848        file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/${area}_plugInfo.json"
849            "${plugInfoContents}")
850        install(
851            FILES "${CMAKE_CURRENT_BINARY_DIR}/${area}_plugInfo.json"
852            DESTINATION "${PXR_INSTALL_SUBDIR}/${area}"
853            RENAME "plugInfo.json"
854        )
855        list(APPEND PXR_EXTRA_PLUGINS "${PXR_INSTALL_SUBDIR}/${area}")
856    endforeach()
857
858    set(PXR_EXTRA_PLUGINS "${PXR_EXTRA_PLUGINS}" CACHE INTERNAL "${help}")
859endfunction() # pxr_setup_third_plugins
860
861function(pxr_toplevel_prologue)
862    # Generate a namespace declaration header, pxr.h, at the top level of
863    # pxr at configuration time.
864    configure_file(${CMAKE_SOURCE_DIR}/pxr/pxr.h.in
865        ${CMAKE_BINARY_DIR}/include/pxr/pxr.h
866    )
867    install(
868        FILES ${CMAKE_BINARY_DIR}/include/pxr/pxr.h
869        DESTINATION include/pxr
870    )
871
872    # Create a monolithic shared library target if we should import one
873    # or create one.
874    if(PXR_BUILD_MONOLITHIC)
875        if(PXR_MONOLITHIC_IMPORT)
876            # Gather the export information for usd_ms.
877            include("${PXR_MONOLITHIC_IMPORT}" OPTIONAL RESULT_VARIABLE found)
878
879            # If the import wasn't found then create it and import it.
880            # This ensures that the build files will be regenerated if
881            # the file's contents change.  If this isn't desired or
882            # write permissions aren't granted the client can configure
883            # first without PXR_MONOLITHIC_IMPORT, build the 'monolithic'
884            # target, build their own shared library and export file,
885            # then configure again with PXR_MONOLITHIC_IMPORT.
886            if(found STREQUAL "NOTFOUND")
887                file(WRITE "${PXR_MONOLITHIC_IMPORT}" "")
888                include("${PXR_MONOLITHIC_IMPORT}")
889            endif()
890
891            # If there's an IMPORTED_LOCATION then its parent must be
892            # the install directory ${CMAKE_INSTALL_PREFIX}.  If it
893            # isn't then we won't be able to find plugInfo.json files
894            # at runtime because they're found relative to the library
895            # that contains pxr/base/lib/plug/initConfig.cpp.  The
896            # exception is if ${PXR_INSTALL_LOCATION} is set;  in that
897            # case we assume the files will be found there regardless
898            # of IMPORTED_LOCATION.  Note, however, that the install
899            # cannot be relocated in this case.
900            if(NOT PXR_INSTALL_LOCATION AND TARGET usd_ms)
901                get_property(location TARGET usd_ms PROPERTY IMPORTED_LOCATION)
902                if(location)
903                    # Remove filename and directory.
904                    get_filename_component(parent "${location}" PATH)
905                    get_filename_component(parent "${parent}" PATH)
906                    get_filename_component(parent "${parent}" ABSOLUTE)
907                    get_filename_component(prefix "${CMAKE_INSTALL_PREFIX}" ABSOLUTE)
908                    if(NOT "${parent}" STREQUAL "${prefix}")
909                        message("IMPORTED_LOCATION for usd_ms ${location} inconsistent with install directory ${CMAKE_INSTALL_PREFIX}.")
910                        message(WARNING "May not find plugins at runtime.")
911                    endif()
912                endif()
913            endif()
914        else()
915            # Note that we ignore BUILD_SHARED_LIBS when building monolithic
916            # when PXR_MONOLITHIC_IMPORT isn't set:  we always build an
917            # archive library from the core libraries and then build a
918            # shared library from that.  BUILD_SHARED_LIBS is still used
919            # for libraries outside of the core.
920
921            # We need at least one source file for the library so we
922            # create an empty one.
923            add_custom_command(
924                OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/usd_ms.cpp"
925                COMMAND ${CMAKE_COMMAND} -E touch "${CMAKE_CURRENT_BINARY_DIR}/usd_ms.cpp"
926            )
927
928            # Our shared library.
929            add_library(usd_ms SHARED "${CMAKE_CURRENT_BINARY_DIR}/usd_ms.cpp")
930            _get_folder("" folder)
931            set_target_properties(usd_ms
932                PROPERTIES
933                    FOLDER "${folder}"
934                    PREFIX "${PXR_LIB_PREFIX}"
935                    IMPORT_PREFIX "${PXR_LIB_PREFIX}"
936            )
937            _get_install_dir("lib" libInstallPrefix)
938            install(
939                TARGETS usd_ms
940                LIBRARY DESTINATION ${libInstallPrefix}
941                ARCHIVE DESTINATION ${libInstallPrefix}
942                RUNTIME DESTINATION ${libInstallPrefix}
943            )
944            if(WIN32)
945                install(
946                    FILES $<TARGET_PDB_FILE:usd_ms>
947                    DESTINATION ${libInstallPrefix}
948                    OPTIONAL
949                )
950            endif()
951        endif()
952    endif()
953
954    # Create a target for shared libraries.  We currently use this only
955    # to test its existence.
956    if(BUILD_SHARED_LIBS OR TARGET usd_ms)
957        add_custom_target(shared_libs)
958    endif()
959
960    # Create a target for targets that require Python.  Each should add
961    # itself as a dependency to the "python" target.
962    if(TARGET shared_libs AND PXR_ENABLE_PYTHON_SUPPORT)
963        add_custom_target(python ALL)
964    endif()
965endfunction() # pxr_toplevel_prologue
966
967function(pxr_toplevel_epilogue)
968    # If we're building a shared monolithic library then link it against
969    # usd_m.
970    if(TARGET usd_ms AND NOT PXR_MONOLITHIC_IMPORT)
971        # We need to use whole-archive to get all the symbols.  Also note
972        # that we carefully avoid adding the usd_m target itself by using
973        # TARGET_FILE.  Linking the usd_m target would link usd_m and
974        # everything it links to.
975        if(MSVC)
976            target_link_libraries(usd_ms
977                PRIVATE
978                    -WHOLEARCHIVE:$<TARGET_FILE:usd_m>
979            )
980        elseif(CMAKE_COMPILER_IS_GNUCXX)
981            target_link_libraries(usd_ms
982                PRIVATE
983                    -Wl,--whole-archive $<TARGET_FILE:usd_m> -Wl,--no-whole-archive
984            )
985        elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
986            target_link_libraries(usd_ms
987                PRIVATE
988                    -Wl,-force_load $<TARGET_FILE:usd_m>
989            )
990        endif()
991
992        # Since we didn't add a dependency to usd_ms on usd_m above, we
993        # manually add it here along with compile definitions, include
994        # directories, etc
995        add_dependencies(usd_ms usd_m)
996
997        # Add the stuff we didn't get because we didn't link against the
998        # usd_m target.
999        target_compile_definitions(usd_ms
1000            PUBLIC
1001                $<TARGET_PROPERTY:usd_m,INTERFACE_COMPILE_DEFINITIONS>
1002        )
1003        target_include_directories(usd_ms
1004            PUBLIC
1005                $<TARGET_PROPERTY:usd_m,INTERFACE_INCLUDE_DIRECTORIES>
1006        )
1007        target_include_directories(usd_ms
1008            SYSTEM
1009            PUBLIC
1010                $<TARGET_PROPERTY:usd_m,INTERFACE_SYSTEM_INCLUDE_DIRECTORIES>
1011        )
1012        foreach(lib ${PXR_OBJECT_LIBS})
1013            get_property(libs TARGET ${lib} PROPERTY INTERFACE_LINK_LIBRARIES)
1014            target_link_libraries(usd_ms
1015                PUBLIC
1016                    ${libs}
1017            )
1018        endforeach()
1019        target_link_libraries(usd_ms
1020            PUBLIC
1021                ${PXR_MALLOC_LIBRARY}
1022                ${PXR_THREAD_LIBS}
1023        )
1024
1025        _pxr_init_rpath(rpath "${libInstallPrefix}")
1026        _pxr_add_rpath(rpath "${CMAKE_INSTALL_PREFIX}/${PXR_INSTALL_SUBDIR}/lib")
1027        _pxr_add_rpath(rpath "${CMAKE_INSTALL_PREFIX}/lib")
1028        _pxr_install_rpath(rpath usd_ms)
1029    endif()
1030
1031    # Setup the plugins in the top epilogue to ensure that everybody has had a
1032    # chance to update PXR_EXTRA_PLUGINS with their plugin paths.
1033    pxr_setup_plugins()
1034endfunction() # pxr_toplevel_epilogue
1035
1036function(pxr_monolithic_epilogue)
1037    # When building a monolithic library we want all API functions to be
1038    # exported.  So add FOO_EXPORTS=1 for every library in PXR_OBJECT_LIBS,
1039    # where FOO is the uppercase version of the library name, to every
1040    # library in PXR_OBJECT_LIBS.
1041    set(exports "")
1042    foreach(lib ${PXR_OBJECT_LIBS})
1043        string(TOUPPER ${lib} uppercaseName)
1044        list(APPEND exports "${uppercaseName}_EXPORTS=1")
1045    endforeach()
1046    foreach(lib ${PXR_OBJECT_LIBS})
1047        set(objects "${objects};\$<TARGET_OBJECTS:${lib}>")
1048        target_compile_definitions(${lib} PRIVATE ${exports})
1049    endforeach()
1050
1051    # Collect all of the objects for all of the core libraries to add to
1052    # the monolithic library.
1053    set(objects "")
1054    foreach(lib ${PXR_OBJECT_LIBS})
1055        set(objects "${objects};\$<TARGET_OBJECTS:${lib}>")
1056    endforeach()
1057
1058    # Add the monolithic library.  This has to be delayed until now
1059    # because $<TARGET_OBJECTS> isn't a real generator expression
1060    # in that it can only appear in the sources of add_library() or
1061    # add_executable();  it can't appear in target_sources().  We
1062    # need at least one source file so we create an empty one
1063    add_custom_command(
1064        OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/usd_m.cpp"
1065        COMMAND ${CMAKE_COMMAND} -E touch "${CMAKE_CURRENT_BINARY_DIR}/usd_m.cpp"
1066    )
1067    add_library(usd_m STATIC "${CMAKE_CURRENT_BINARY_DIR}/usd_m.cpp" ${objects})
1068
1069    _get_folder("" folder)
1070    set_target_properties(usd_m
1071        PROPERTIES
1072            FOLDER "${folder}"
1073            POSITION_INDEPENDENT_CODE ON
1074            PREFIX "${PXR_LIB_PREFIX}"
1075            IMPORT_PREFIX "${PXR_LIB_PREFIX}"
1076    )
1077
1078    # Adding $<TARGET_OBJECTS:foo> will not bring along compile
1079    # definitions, include directories, etc.  Since we'll want those
1080    # attached to usd_m we explicitly add them.
1081    foreach(lib ${PXR_OBJECT_LIBS})
1082        target_compile_definitions(usd_m
1083            PUBLIC
1084                $<TARGET_PROPERTY:${lib},INTERFACE_COMPILE_DEFINITIONS>
1085        )
1086        target_include_directories(usd_m
1087            PUBLIC
1088                $<TARGET_PROPERTY:${lib},INTERFACE_INCLUDE_DIRECTORIES>
1089        )
1090        target_include_directories(usd_m
1091            SYSTEM
1092            PUBLIC
1093                $<TARGET_PROPERTY:${lib},INTERFACE_SYSTEM_INCLUDE_DIRECTORIES>
1094        )
1095
1096        get_property(libs TARGET ${lib} PROPERTY INTERFACE_LINK_LIBRARIES)
1097        target_link_libraries(usd_m
1098            PUBLIC
1099                ${libs}
1100        )
1101    endforeach()
1102
1103    # Manual export targets.  We can't use install(EXPORT) because usd_m
1104    # depends on OBJECT libraries which cannot be exported yet must be
1105    # in order to export usd_m.  We also have boilerplate for usd_ms, the
1106    # externally built monolithic shared library containing usd_m.  The
1107    # client should replace the FIXMEs with the appropriate paths or
1108    # use the usd_m export to build against and generate a usd_ms export.
1109    set(export "")
1110    set(export "${export}add_library(usd_m STATIC IMPORTED)\n")
1111    set(export "${export}set_property(TARGET usd_m PROPERTY IMPORTED_LOCATION $<TARGET_FILE:usd_m>)\n")
1112    set(export "${export}set_property(TARGET usd_m PROPERTY INTERFACE_COMPILE_DEFINITIONS $<TARGET_PROPERTY:usd_m,INTERFACE_COMPILE_DEFINITIONS>)\n")
1113    set(export "${export}set_property(TARGET usd_m PROPERTY INTERFACE_INCLUDE_DIRECTORIES $<TARGET_PROPERTY:usd_m,INTERFACE_INCLUDE_DIRECTORIES>)\n")
1114    set(export "${export}set_property(TARGET usd_m PROPERTY INTERFACE_SYSTEM_INCLUDE_DIRECTORIES $<TARGET_PROPERTY:usd_m,INTERFACE_SYSTEM_INCLUDE_DIRECTORIES>)\n")
1115    set(export "${export}set_property(TARGET usd_m PROPERTY INTERFACE_LINK_LIBRARIES $<TARGET_PROPERTY:usd_m,INTERFACE_LINK_LIBRARIES>)\n")
1116    file(GENERATE
1117        OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/usd-targets-$<CONFIG>.cmake"
1118        CONTENT "${export}"
1119    )
1120    set(export "")
1121    set(export "${export}# Boilerplate for export of usd_ms.  Replace FIXMEs with appropriate paths\n")
1122    set(export "${export}# or include usd-targets-$<CONFIG>.cmake in your own build and generate your\n")
1123    set(export "${export}# own export file.  Configure with PXR_MONOLITHIC_IMPORT set to the path of\n")
1124    set(export "${export}# the export file.\n")
1125    set(export "${export}add_library(usd_ms SHARED IMPORTED)\n")
1126    set(export "${export}set_property(TARGET usd_ms PROPERTY IMPORTED_LOCATION FIXME)\n")
1127    set(export "${export}#set_property(TARGET usd_ms PROPERTY IMPORTED_IMPLIB FIXME)\n")
1128    set(export "${export}set_property(TARGET usd_ms PROPERTY INTERFACE_COMPILE_DEFINITIONS $<TARGET_PROPERTY:usd_m,INTERFACE_COMPILE_DEFINITIONS>)\n")
1129    set(export "${export}set_property(TARGET usd_ms PROPERTY INTERFACE_INCLUDE_DIRECTORIES $<TARGET_PROPERTY:usd_m,INTERFACE_INCLUDE_DIRECTORIES>)\n")
1130    set(export "${export}set_property(TARGET usd_ms PROPERTY INTERFACE_SYSTEM_INCLUDE_DIRECTORIES $<TARGET_PROPERTY:usd_m,INTERFACE_SYSTEM_INCLUDE_DIRECTORIES>)\n")
1131    set(export "${export}set_property(TARGET usd_ms PROPERTY INTERFACE_LINK_LIBRARIES $<TARGET_PROPERTY:usd_m,INTERFACE_LINK_LIBRARIES>)\n")
1132    file(GENERATE
1133        OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/usd-imports-$<CONFIG>.cmake"
1134        CONTENT "${export}"
1135    )
1136
1137    # Convenient name for building the monolithic library.
1138    add_custom_target(monolithic
1139        DEPENDS
1140            usd_m
1141        COMMAND ${CMAKE_COMMAND} -E copy
1142            "${CMAKE_CURRENT_BINARY_DIR}/usd-targets-$<CONFIG>.cmake"
1143            "${CMAKE_BINARY_DIR}/usd-targets-$<CONFIG>.cmake"
1144        COMMAND ${CMAKE_COMMAND} -E copy
1145            "${CMAKE_CURRENT_BINARY_DIR}/usd-imports-$<CONFIG>.cmake"
1146            "${CMAKE_BINARY_DIR}/usd-imports-$<CONFIG>.cmake"
1147        COMMAND ${CMAKE_COMMAND} -E echo Export file: ${CMAKE_BINARY_DIR}/usd-targets-$<CONFIG>.cmake
1148        COMMAND ${CMAKE_COMMAND} -E echo Import file: ${CMAKE_BINARY_DIR}/usd-imports-$<CONFIG>.cmake
1149    )
1150endfunction() # pxr_monolithic_epilogue
1151
1152function(pxr_core_prologue)
1153    set(_building_core TRUE PARENT_SCOPE)
1154    if(PXR_BUILD_MONOLITHIC)
1155        set(_building_monolithic TRUE PARENT_SCOPE)
1156    endif()
1157endfunction() # pxr_core_prologue
1158
1159function(pxr_core_epilogue)
1160    if(_building_core)
1161        if(_building_monolithic)
1162            pxr_monolithic_epilogue()
1163            set(_building_monolithic FALSE PARENT_SCOPE)
1164        endif()
1165        if(PXR_ENABLE_PYTHON_SUPPORT)
1166            pxr_setup_python()
1167        endif()
1168        set(_building_core FALSE PARENT_SCOPE)
1169    endif()
1170endfunction() # pxr_core_epilogue
1171