#############################################################################
# $Id: CMake.NCBIptb.cmake 620014 2020-11-13 18:30:31Z gouriano $
#############################################################################
#############################################################################
##
##  NCBI CMake wrapper
##    Author: Andrei Gourianov, gouriano@ncbi
##
##---------------------------------------------------------------------------
##  in CMakeLists.txt:
##    NCBI_add_subdirectory( list of subdirectories)
##    NCBI_add_library(      list of libraries)
##    NCBI_add_app(          list of apps)
##---------------------------------------------------------------------------
##  the following calls in CMakeLists.txt affect all projects in current dir and all subdirs
##    NCBI_headers( list of headers)
##    NCBI_disable_pch() / NCBI_enable_pch()
##    NCBI_requires( list of components)
##    NCBI_optional_components(  list of components)
##    NCBI_add_definitions(         list of compiler definitions)
##    NCBI_add_include_directories( list of directories)
##    NCBI_uses_toolkit_libraries(  list of libraries)
##    NCBI_uses_external_libraries( list of libraries)
##    NCBI_project_tags(list of tags)
##    
##---------------------------------------------------------------------------
##  in CMakeLists.xxx.[lib|app].txt - all calls affect current project only
##    NCBI_begin_lib(name) or NCBI_begin_app(name)
##
##      NCBI_sources(   list of source files)
##      NCBI_generated_sources(   list of source files) - file extension is mandatory
##      NCBI_headers(   list of header files) - only relative paths and masks are allowed
##      NCBI_resources( list of resource files) - file extension is mandatory
##      NCBI_dataspecs( list of data specs - ASN, DTD, XSD etc) - file extension is mandatory
##
##      NCBI_requires( list of components)
##      NCBI_optional_components(  list of components)
##
##      NCBI_enable_pch() / NCBI_disable_pch() - no arguments
##      NCBI_disable_pch_for( list of source files)
##      NCBI_set_pch_header( header file)
##      NCBI_set_pch_define( macro to define)
##
##      NCBI_uses_toolkit_libraries(  list of libraries)
##      NCBI_uses_external_libraries( list of libraries)
##      NCBI_add_definitions(         list of compiler definitions)
##      NCBI_add_include_directories( list of directories)
##
##      NCBI_hosts_projects(list of parts) - used to assemble composite shared libraries
##
##      NCBI_set_property(property value)
##      NCBI_project_tags(     list of tags)
##      NCBI_project_watchers( list of watchers)
##
##      Testing:
##      short form
##          NCBI_add_test( test command) - empty command means run the app with no arguments
##      long form
##          NCBI_begin_test(name) - name is optional
##              NCBI_set_test_command(command, maybe with arguments)
##           OR NCBI_set_test_arguments(arguments only)
##              NCBI_set_test_assets(list of assets) - required files and directories
##              NCBI_set_test_timeout(seconds)
##              NCBI_set_test_requires(list of components)
##              NCBI_set_test_resources(list of test resources)
##              NCBI_set_test_labels(list of labels)
##          NCBI_end_test()
##
##    NCBI_end_lib(result) or NCBI_end_app(result) - argument 'result' is optional
##
##---------------------------------------------------------------------------
##  custom targets
##  in CMakeLists.txt:
##    NCBI_add_target( list of targets)
##
##  in CMakeLists.xxx.txt - add function which defines target, then add target:
##    function(xxx_definition)      - the function name must be unique
##      ...
##      add_custom_target(name ...) - the same name as in NCBI_begin_custom_target
##    endfunction()
##
##    NCBI_begin_custom_target(name)
##      NCBI_requires( list of components)
##      NCBI_custom_target_dependencies(list of toolkit libraries or apps)
##      NCBI_custom_target_definition( xxx_definition) - function name defined above
##    NCBI_end_custom_target(result) - argument 'result' is optional
##
##---------------------------------------------------------------------------
##  extensions
##    NCBI_register_hook(event callback_function)
##      events:
##        TARGET_PARSED - a project is parsed
##        ALL_PARSED    - all projects in the source tree are parsed
##        COLLECTED     - all build targets are collected
##        TARGET_ADDED  - build target is added
##        ALL_ADDED     - all targets are added
##        DATASPEC      - process data specification
##  
#############################################################################


#############################################################################
# deprecated
macro(NCBI_add_root_subdirectory)
    message(WARNING "NCBI_add_root_subdirectory is deprecated, use NCBI_add_subdirectory instead")
    NCBI_add_subdirectory(${ARGV})
endmacro()

#############################################################################
function(NCBI_add_subdirectory)
    if(NCBI_PTBMODE_PARTS)
        return()
    endif()

    if(NOT DEFINED NCBI_CURRENT_SOURCE_DIR)
        set(NCBI_CURRENT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
    endif()
    if("${NCBI_CURRENT_SOURCE_DIR}" STREQUAL "${NCBITK_SRC_ROOT}")
        set(NCBI_TREE_ROOT    ${NCBITK_TREE_ROOT})
        set(NCBI_SRC_ROOT     ${NCBITK_SRC_ROOT})
        set(NCBI_INC_ROOT     ${NCBITK_INC_ROOT})
    elseif("${NCBI_CURRENT_SOURCE_DIR}" STREQUAL "${NCBITK_TREE_ROOT}")
        set(NCBI_TREE_ROOT    ${NCBITK_TREE_ROOT})
        set(NCBI_SRC_ROOT     ${NCBITK_TREE_ROOT})
        set(NCBI_INC_ROOT     ${NCBITK_TREE_ROOT})
    endif()

    if(NOT NCBI_PTB_HAS_ROOT)
        NCBI_internal_analyze_tree()
    endif()

    if(NCBI_PTBMODE_COLLECT_DEPS)
        set(_curdir ${NCBI_CURRENT_SOURCE_DIR})
        foreach(_sub IN LISTS ARGV)
            if (EXISTS "${_curdir}/${_sub}/CMakeLists.txt")
                set(NCBI_CURRENT_SOURCE_DIR ${_curdir}/${_sub})
                NCBI_internal_include("${_curdir}/${_sub}/CMakeLists.txt")
            else()
                message("WARNING: directory not found: ${_curdir}/${_sub}")
            endif()
        endforeach()
    else()
        foreach(_sub IN LISTS ARGV)
            set(NCBI_CURRENT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/${_sub})
            if(DEFINED NCBI_PTB_ALLOWED_DIRS)
                set(_is_good FALSE)
                foreach(_dir IN LISTS NCBI_PTB_ALLOWED_DIRS)
                    string(FIND ${_dir} ${NCBI_CURRENT_SOURCE_DIR} _pos)
                    if(${_pos} EQUAL 0)
                        set(_is_good TRUE)
                        break()
                    endif()
                endforeach()
            else()
                NCBI_internal_process_project_filters( _is_good)
                if(NOT _is_good)
                    if(NOT "${NCBI_PTBCFG_PROJECT_LIST}" STREQUAL "")
                        foreach(_dir IN LISTS NCBI_PTBCFG_PROJECT_LIST)
                            string(FIND "${NCBI_SRC_ROOT}/${_dir}" "${NCBI_CURRENT_SOURCE_DIR}" _pos)
                            if(${_pos} EQUAL 0)
                                set(_is_good TRUE)
                                break()
                            endif()
                        endforeach()
                    endif()
                endif()
            endif()
            if (_is_good AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${_sub}/CMakeLists.txt")
                add_subdirectory(${_sub})
            endif()
        endforeach()
    endif()
endfunction()

#############################################################################
function(NCBI_add_library)
    if(NCBI_PTBMODE_PARTS)
        return()
    endif()
    if(NOT NCBI_PTBMODE_COLLECT_DEPS)
        set(NCBI_CURRENT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
    endif()
    set(NCBI_PROJECT_expected library)
    foreach(_lib IN LISTS ARGV)
        if (EXISTS ${NCBI_CURRENT_SOURCE_DIR}/CMakeLists.${_lib}.lib.txt)
            NCBI_internal_include(${NCBI_CURRENT_SOURCE_DIR}/CMakeLists.${_lib}.lib.txt)
        elseif (EXISTS ${NCBI_CURRENT_SOURCE_DIR}/CMakeLists.${_lib}.asn.txt)
            NCBI_internal_include(${NCBI_CURRENT_SOURCE_DIR}/CMakeLists.${_lib}.asn.txt)
        elseif (EXISTS ${NCBI_CURRENT_SOURCE_DIR}/${_lib} AND NOT IS_DIRECTORY ${NCBI_CURRENT_SOURCE_DIR}/${_lib})
            NCBI_internal_include(${NCBI_CURRENT_SOURCE_DIR}/${_lib})
        else()
            message("WARNING: Library project not found: ${_lib} (${NCBI_CURRENT_SOURCE_DIR})")
        endif()
    endforeach()
    unset(NCBI_PROJECT_expected)
endfunction()

#############################################################################
function(NCBI_add_app)
    if(NCBI_PTBMODE_PARTS)
        return()
    endif()
    if(NOT NCBI_PTBMODE_COLLECT_DEPS)
        set(NCBI_CURRENT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
    endif()
    set(NCBI_PROJECT_expected app)
    foreach(_app IN LISTS ARGV)
        if (EXISTS ${NCBI_CURRENT_SOURCE_DIR}/CMakeLists.${_app}.app.txt)
            NCBI_internal_include(${NCBI_CURRENT_SOURCE_DIR}/CMakeLists.${_app}.app.txt)
        elseif (EXISTS ${NCBI_CURRENT_SOURCE_DIR}/${_app} AND NOT IS_DIRECTORY ${NCBI_CURRENT_SOURCE_DIR}/${_app})
            NCBI_internal_include(${NCBI_CURRENT_SOURCE_DIR}/${_app})
        else()
            message("WARNING: App project not found: ${_app} (${NCBI_CURRENT_SOURCE_DIR})")
        endif()
    endforeach()
    unset(NCBI_PROJECT_expected)
endfunction()

#############################################################################
function(NCBI_add_target)
    if(NCBI_PTBMODE_PARTS)
        return()
    endif()
    if(NOT NCBI_PTBMODE_COLLECT_DEPS)
        set(NCBI_CURRENT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
    endif()
    foreach(_prj IN LISTS ARGV)
        if (EXISTS ${NCBI_CURRENT_SOURCE_DIR}/CMakeLists.${_prj}.txt)
            NCBI_internal_include(${NCBI_CURRENT_SOURCE_DIR}/CMakeLists.${_prj}.txt)
        elseif (EXISTS ${NCBI_CURRENT_SOURCE_DIR}/${_prj} AND NOT IS_DIRECTORY ${NCBI_CURRENT_SOURCE_DIR}/${_prj})
            NCBI_internal_include(${NCBI_CURRENT_SOURCE_DIR}/${_prj})
        else()
            message("WARNING: Target not found: ${_prj} (${NCBI_CURRENT_SOURCE_DIR})")
        endif()
    endforeach()
endfunction()

#############################################################################
macro(NCBI_begin_lib _name)
    if( NOT NCBI_PTBMODE_PARTS AND NOT "${NCBI_PROJECT_expected}" STREQUAL "" AND NOT "${NCBI_PROJECT_expected}" STREQUAL "library")
        message(SEND_ERROR "${NCBI_CURRENT_SOURCE_DIR}/${NCBI_PROJECT}: Unexpected NCBI_begin_lib call")
    endif()
    if(NCBI_PTBMODE_PARTS)
        set(_libname ${_name}.part)
    else()
        set(_libname ${_name})
    endif()
    if (DEFINED NCBI_EXTERNAL_TREE_ROOT AND TARGET ${_name})
        set(_libname ${_libname}.local)
        if (NCBI_PTBMODE_COLLECT_DEPS)
            set_property(GLOBAL PROPERTY NCBI_PTBPROP_LOCAL_${_name} "${_libname}")
            message(STATUS "Imported target ${_name} will be replaced with local ${_libname} (${NCBI_CURRENT_SOURCE_DIR})")
        endif()
    endif()
    set(NCBI_PROJECT_lib ${_libname})
    set(NCBI_PROJECT ${_libname})
    set(NCBI_${NCBI_PROJECT}_OUTPUT ${_name})
    if ("${ARGC}" GREATER "1")
        if (NOT "${ARGV1}" STREQUAL "STATIC" AND NOT "${ARGV1}" STREQUAL "SHARED")
            message(SEND_ERROR "${NCBI_CURRENT_SOURCE_DIR}/${NCBI_PROJECT}: Unsupported lib type: ${ARGV1}")
        endif()
        if(BUILD_SHARED_LIBS)
            set(NCBI_${NCBI_PROJECT}_TYPE ${ARGV1})
        else()
            set(NCBI_${NCBI_PROJECT}_TYPE STATIC)
        endif()
    else()
        if(BUILD_SHARED_LIBS)
            if(WIN32 OR XCODE)
                set(NCBI_${NCBI_PROJECT}_TYPE STATIC)
            else()
                set(NCBI_${NCBI_PROJECT}_TYPE SHARED)
            endif()
        else()
            set(NCBI_${NCBI_PROJECT}_TYPE STATIC)
        endif()
    endif()
    set(NCBI_PROJECT_PARTNAME ${_name})
    set(NCBI_PROJECT_ID ${_name}.${NCBI_${NCBI_PROJECT}_TYPE})
endmacro()

#############################################################################
macro(NCBI_end_lib)
    if(NOT DEFINED NCBI_PROJECT_lib)
        message(SEND_ERROR "${NCBI_CURRENT_SOURCE_DIR}/${NCBI_PROJECT}: Unexpected NCBI_end_lib call")
    endif()
    NCBI_internal_add_project(${ARGV})
    unset(NCBI_PROJECT)
endmacro()

#############################################################################
macro(NCBI_begin_app _name)
    if( NOT NCBI_PTBMODE_PARTS AND NOT "${NCBI_PROJECT_expected}" STREQUAL "" AND NOT "${NCBI_PROJECT_expected}" STREQUAL "app")
        message(SEND_ERROR "${NCBI_CURRENT_SOURCE_DIR}/${NCBI_PROJECT}: Unexpected NCBI_begin_app call")
    endif()
    if(NCBI_PTBMODE_PARTS)
        set(_appname ${_name}.part)
    else()
        set(_appname ${_name})
    endif()
    if (DEFINED NCBI_EXTERNAL_TREE_ROOT AND TARGET ${_name})
        set(_appname ${_appname}.local)
        if (NCBI_PTBMODE_COLLECT_DEPS)
            set_property(GLOBAL PROPERTY NCBI_PTBPROP_LOCAL_${_name} "${_appname}")
            message(STATUS "Imported target ${_name} will be replaced with local ${_appname} (${NCBI_CURRENT_SOURCE_DIR})")
        endif()
    endif()
    set(NCBI_PROJECT_app ${_appname})
    if (NOT DEFINED NCBI_EXTERNAL_TREE_ROOT)
        get_property(_dir GLOBAL PROPERTY NCBI_PTBPROP_DIR_${_name})
        if (NOT ${_dir} STREQUAL "")
            if (NCBI_PTBMODE_COLLECT_DEPS OR TARGET ${_name})
                set(_appname ${_appname}-app)
            endif()
        elseif(NOT NCBI_PTBCFG_ENABLE_COLLECTOR)
            if (TARGET ${_name})
                set(_appname ${_appname}-app)
            endif()
        endif()
    endif()
    set(NCBI_PROJECT ${_appname})
    set(NCBI_${NCBI_PROJECT}_OUTPUT ${_name})
    if ("${ARGC}" GREATER "1")
        if ("${ARGV1}" STREQUAL "GUI")
            set(NCBI_${NCBI_PROJECT}_TYPE GUIAPP)
        elseif ("${ARGV1}" STREQUAL "CONSOLE")
            set(NCBI_${NCBI_PROJECT}_TYPE CONSOLEAPP)
        else()
            message(SEND_ERROR "${NCBI_CURRENT_SOURCE_DIR}/${NCBI_PROJECT}: Unsupported app type: ${ARGV1}")
        endif()
    else()
        set(NCBI_${NCBI_PROJECT}_TYPE CONSOLEAPP)
    endif()
    set(NCBI_PROJECT_PARTNAME ${_name})
    set(NCBI_PROJECT_ID ${_name}.${NCBI_${NCBI_PROJECT}_TYPE})
endmacro()

#############################################################################
macro(NCBI_end_app)
    if(NOT DEFINED NCBI_PROJECT_app)
        message(SEND_ERROR "${NCBI_CURRENT_SOURCE_DIR}/${NCBI_PROJECT}: Unexpected NCBI_end_app call")
    endif()
    NCBI_internal_add_project(${ARGV})
    unset(NCBI_PROJECT)
endmacro()

#############################################################################
macro(NCBI_begin_custom_target _name)
    set(NCBI_PROJECT_custom ${_name})
    set(NCBI_PROJECT ${_name})
    set(NCBI_${NCBI_PROJECT}_TYPE CUSTOM)
    set(NCBI_PROJECT_ID ${_name}.${NCBI_${NCBI_PROJECT}_TYPE})
endmacro()

#############################################################################
macro(NCBI_end_custom_target)
    if(NOT DEFINED NCBI_PROJECT_custom)
        message(SEND_ERROR "${NCBI_CURRENT_SOURCE_DIR}/${NCBI_PROJECT}: Unexpected NCBI_end_custom_target call")
    endif()
    if(NOT DEFINED NCBI_${NCBI_PROJECT}_DEFINITION)
        message(FATAL_ERROR "${NCBI_PROJECT} (${NCBI_CURRENT_SOURCE_DIR}): Custom project definition not provided")
    endif()
    NCBI_internal_add_project(${ARGV})
    unset(NCBI_PROJECT)
endmacro()

#############################################################################
macro(NCBI_custom_target_definition _def)
    set(NCBI_${NCBI_PROJECT}_DEFINITION ${_def})
endmacro()

#############################################################################
macro(NCBI_custom_target_dependencies)
    set(NCBI_${NCBI_PROJECT}_NCBILIB ${NCBI_${NCBI_PROJECT}_NCBILIB} "${ARGV}")
endmacro()

#############################################################################
macro(NCBI_sources)
    set(NCBI_${NCBI_PROJECT}_SOURCES ${NCBI_${NCBI_PROJECT}_SOURCES} "${ARGV}")
endmacro()
macro(NCBI_generated_sources)
    set(NCBI_${NCBI_PROJECT}_GENERATED_SOURCES ${NCBI_${NCBI_PROJECT}_GENERATED_SOURCES} "${ARGV}")
endmacro()

#############################################################################
macro(NCBI_headers)
    set(NCBI_${NCBI_PROJECT}_HEADERS ${NCBI_${NCBI_PROJECT}_HEADERS} "${ARGV}")
endmacro()

#############################################################################
macro(NCBI_resources)
    set(NCBI_${NCBI_PROJECT}_RESOURCES ${NCBI_${NCBI_PROJECT}_RESOURCES} "${ARGV}")
endmacro()

#############################################################################
macro(NCBI_dataspecs)
    set(NCBI_${NCBI_PROJECT}_DATASPEC ${NCBI_${NCBI_PROJECT}_DATASPEC} "${ARGV}")
endmacro()

#############################################################################
macro(NCBI_hosts_projects)
    set(NCBI_${NCBI_PROJECT}_PARTS ${NCBI_${NCBI_PROJECT}_PARTS} "${ARGV}")
    if(NOT DEFINED NCBI_PROJECT_ID_COMPOSITE)
        set(NCBI_PROJECT_ID_COMPOSITE ${NCBI_PROJECT_ID})
        set(NCBI_PROJECT_ID ${NCBI_PROJECT_ID}.COMPOSITE)
    endif()
endmacro()

macro(NCBI_hosts_virtual_projects)
    set(NCBI_${NCBI_PROJECT}_VIRTPARTS ${NCBI_${NCBI_PROJECT}_VIRTPARTS} "${ARGV}")
endmacro()

#############################################################################
macro(NCBI_requires)
    set(NCBI_${NCBI_PROJECT}_REQUIRES ${NCBI_${NCBI_PROJECT}_REQUIRES} "${ARGV}")
endmacro()

#############################################################################
macro(NCBI_optional_components)
    set(NCBI_${NCBI_PROJECT}_COMPONENTS ${NCBI_${NCBI_PROJECT}_COMPONENTS} "${ARGV}")
endmacro()

#############################################################################
macro(NCBI_enable_pch)
    set(NCBI_${NCBI_PROJECT}_USEPCH ${NCBI_DEFAULT_USEPCH})
endmacro()
macro(NCBI_disable_pch)
    set(NCBI_${NCBI_PROJECT}_USEPCH OFF)
endmacro()

#############################################################################
macro(NCBI_disable_pch_for)
    set(NCBI_${NCBI_PROJECT}_NOPCH ${NCBI_${NCBI_PROJECT}_NOPCH} "${ARGV}")
endmacro()

#############################################################################
macro(NCBI_set_pch_header)
    set(NCBI_${NCBI_PROJECT}_PCH "${ARGV}")
endmacro()

#############################################################################
macro(NCBI_set_pch_define)
    set(NCBI_${NCBI_PROJECT}_PCH_DEFINE "${ARGV}")
endmacro()

#############################################################################
macro(NCBI_set_dllentry)
    set(NCBI_${NCBI_PROJECT}_DLLENTRY "${ARGV}")
endmacro()

#############################################################################
macro(NCBI_set_guientry)
    set(NCBI_${NCBI_PROJECT}_GUIENTRY "${ARGV}")
endmacro()

#############################################################################
macro(NCBI_uses_toolkit_libraries)
    set(NCBI_${NCBI_PROJECT}_NCBILIB ${NCBI_${NCBI_PROJECT}_NCBILIB} "${ARGV}")
endmacro()

#############################################################################
macro(NCBI_uses_external_libraries)
    set(NCBI_${NCBI_PROJECT}_EXTLIB ${NCBI_${NCBI_PROJECT}_EXTLIB} "${ARGV}")
endmacro()

#############################################################################
macro(NCBI_add_include_directories)
    set(NCBI_${NCBI_PROJECT}_INCLUDES ${NCBI_${NCBI_PROJECT}_INCLUDES} "${ARGV}")
endmacro()

#############################################################################
macro(NCBI_add_definitions)
    set(NCBI_${NCBI_PROJECT}_DEFINES ${NCBI_${NCBI_PROJECT}_DEFINES} "${ARGV}")
endmacro()

#############################################################################
macro(NCBI_set_property _property _value)
    set(NCBI_${NCBI_PROJECT}_PROPERTY_${_property} ${_value})
endmacro()

#############################################################################
macro(NCBI_project_tags)
    set(NCBI_${NCBI_PROJECT}_PROJTAG ${NCBI_${NCBI_PROJECT}_PROJTAG} "${ARGV}")
endmacro()

#############################################################################
macro(NCBI_project_watchers)
    set(NCBI_${NCBI_PROJECT}_WATCHER ${NCBI_${NCBI_PROJECT}_WATCHER} "${ARGV}")
endmacro()

#############################################################################
#############################################################################
#############################################################################
macro(NCBI_begin_test)
    if(DEFINED NCBI_${NCBI_PROJECT}_TEST)
        message(SEND_ERROR "${NCBI_CURRENT_SOURCE_DIR}/${NCBI_PROJECT}: Unexpected NCBI_begin_test call")
    endif()
    if (DEFINED NCBITEST_${NCBI_PROJECT}_NUM)
        math(EXPR NCBITEST_${NCBI_PROJECT}_NUM "${NCBITEST_${NCBI_PROJECT}_NUM} + 1")
    endif()
    set(_testalias "")
    if ("${ARGC}" GREATER "0")
        set(_testname "${ARGV}")
        set(_testalias "${_testname}")
        if ( "${_testname}" STREQUAL "")
            set(_testname "${NCBI_PROJECT}${NCBITEST_${NCBI_PROJECT}_NUM}")
        endif()
    else()
        set(_testname "${NCBI_PROJECT}${NCBITEST_${NCBI_PROJECT}_NUM}")
    endif()
    set(NCBI_${NCBI_PROJECT}_TEST "${_testname}")
    set(NCBITEST_${NCBI_${NCBI_PROJECT}_TEST}_TESTALIAS "${_testalias}")
    if (NOT DEFINED NCBITEST_${NCBI_PROJECT}_NUM)
        set(NCBITEST_${NCBI_PROJECT}_NUM "1")
    endif()
endmacro()

##############################################################################
macro(NCBI_set_test_command)
    set( _args ${ARGV})
    list(GET _args 0 _cmd)
    list(REMOVE_AT _args 0) 
    if ( "${_cmd}" STREQUAL "${NCBI_PROJECT}")
        set(_cmd "${NCBI_${NCBI_PROJECT}_OUTPUT}")
        if (${NCBI_${NCBI_PROJECT}_TYPE} STREQUAL "CONSOLEAPP" OR ${NCBI_${NCBI_PROJECT}_TYPE} STREQUAL "GUIAPP")
           set(_cmd "${_cmd}${CMAKE_EXECUTABLE_SUFFIX}")
        endif()
    endif()
    set(NCBITEST_${NCBI_${NCBI_PROJECT}_TEST}_CMD "${_cmd}")
    set(NCBITEST_${NCBI_${NCBI_PROJECT}_TEST}_ARG "${_args}")
endmacro()

##############################################################################
macro(NCBI_set_test_arguments)
    set(NCBITEST_${NCBI_${NCBI_PROJECT}_TEST}_ARG "${ARGV}")
endmacro()

##############################################################################
macro(NCBI_set_test_assets)
    set(NCBITEST_${NCBI_${NCBI_PROJECT}_TEST}_ASSETS "${ARGV}")
endmacro()

##############################################################################
macro(NCBI_set_test_timeout)
    set(NCBITEST_${NCBI_${NCBI_PROJECT}_TEST}_TIMEOUT "${ARGV}")
endmacro()

##############################################################################
macro(NCBI_set_test_requires)
    set(NCBITEST_${NCBI_${NCBI_PROJECT}_TEST}_REQUIRES "${ARGV}")
endmacro()

##############################################################################
macro(NCBI_set_test_resources)
    set(NCBITEST_${NCBI_${NCBI_PROJECT}_TEST}_RESOURCES "${ARGV}")
endmacro()

##############################################################################
macro(NCBI_set_test_labels)
    set(NCBITEST_${NCBI_${NCBI_PROJECT}_TEST}_LABELS "${ARGV}")
endmacro()

##############################################################################
macro(NCBI_define_test_resource _name _amount)
    if(DEFINED NCBITEST_RESOURCE_${_name}_AMOUNT)
        message(SEND_ERROR "${NCBI_CURRENT_SOURCE_DIR}: Test resource ${_name} already defined")
    endif()
    set(NCBITEST_RESOURCE_${_name}_AMOUNT ${_amount})
endmacro()

##############################################################################
macro(NCBI_end_test)
    set(NCBI_${NCBI_PROJECT}_ALLTESTS ${NCBI_${NCBI_PROJECT}_ALLTESTS} ${NCBI_${NCBI_PROJECT}_TEST})
    unset(NCBI_${NCBI_PROJECT}_TEST)
endmacro()

##############################################################################
macro(NCBI_add_test)
    if ("${ARGC}" GREATER "0")
        set(_cmd "${ARGV}")
        if ( "${_cmd}" STREQUAL "")
            set(_cmd "${NCBI_PROJECT}")
        endif()
    else()
        set(_cmd "${NCBI_PROJECT}")
    endif()
    NCBI_begin_test()
    NCBI_set_test_command(${_cmd})
    NCBI_end_test()
endmacro()

##############################################################################
function(NCBI_import_hostinfo _file)
    if(NOT EXISTS ${_file})
        return()
    endif()
    file(STRINGS ${_file} _hostinfo)
    if (NOT "${_hostinfo}" STREQUAL "")
        foreach( _item IN LISTS _hostinfo)
            string(REPLACE " " ";" _item ${_item})
            if (NOT "${_item}" STREQUAL "")
                list(GET _item 0 _prj)
                list(GET _item 1 _host)
                set_property(GLOBAL PROPERTY NCBI_PTBPROP_HOST_${_prj} ${_host})
            endif()
        endforeach()
    endif()
endfunction()

##############################################################################
function(NCBI_register_hook _event _callback)
    if("${_event}" STREQUAL "TARGET_PARSED")
        variable_watch(NCBI_PTB_CALLBACK_TARGET_PARSED ${_callback})
    elseif("${_event}" STREQUAL "ALL_PARSED")
        variable_watch(NCBI_PTB_CALLBACK_ALL_PARSED ${_callback})
    elseif("${_event}" STREQUAL "COLLECTED")
        variable_watch(NCBI_PTB_CALLBACK_COLLECTED ${_callback})
    elseif("${_event}" STREQUAL "TARGET_ADDED")
        variable_watch(NCBI_PTB_CALLBACK_TARGET_ADDED ${_callback})
    elseif("${_event}" STREQUAL "ALL_ADDED")
        variable_watch(NCBI_PTB_CALLBACK_ALL_ADDED ${_callback})
    elseif("${_event}" STREQUAL "DATASPEC")
        if ("${ARGC}" LESS "3")
            message(FATAL_ERROR "DATASPEC hook requires a list of file extensions (${_callback})")
        endif()
        foreach( _ext IN LISTS ARGV2)
            string(TOLOWER ${_ext} _ext)
            variable_watch(NCBI_PTB_CALLBACK_DATASPEC${_ext} ${_callback})
        endforeach()
    else()
        message(SEND_ERROR "An attempt to register hook for an unknown event: ${_event} (${_callback})")
    endif()
endfunction()

##############################################################################
macro(NCBI_util_elapsed _value)
    if(DEFINED NCBI_TIMESTAMP_START)
        string(TIMESTAMP _curtime "%s")
        math(EXPR _delta "${_curtime} - ${NCBI_TIMESTAMP_START}")
        string(TIMESTAMP _curtime "%H:%M:%S")
        set(${_value} "${_curtime} (${_delta}s)")
    else()
        string(TIMESTAMP ${_value} "%H:%M:%S")
    endif()
endmacro()

##############################################################################
macro(NCBI_util_parse_sign _input _value _negative)
    string(SUBSTRING ${_input} 0 1 _sign)
    if ("${_sign}" STREQUAL "-")
        string(SUBSTRING ${_input} 1 -1 ${_value})
        set(${_negative} ON)
    else()
        set(${_value} ${_input})
        set(${_negative} OFF)
    endif()
endmacro()

##############################################################################
macro(NCBI_util_get_value _value _result)
    if (DEFINED NCBI_${NCBI_PROJECT}_${_value})
        set(${_result} ${NCBI_${NCBI_PROJECT}_${_value}})
    elseif (DEFINED NCBI__${_value})
        set(${_result} ${NCBI__${_value}})
    else()
        set(${_result} ${NCBI_DEFAULT_${_value}})
    endif()
endmacro()

##############################################################################
function(NCBI_util_match_path _value _pattern _result)
    file(RELATIVE_PATH _rel_value "${NCBI_SRC_ROOT}" "${_value}")
    file(RELATIVE_PATH _rel_pattern "${NCBI_SRC_ROOT}" "${_pattern}")
    if ("${_rel_value}" MATCHES "^${_rel_pattern}")
        set(${_result} TRUE PARENT_SCOPE)
    else()
        set(${_result} FALSE PARENT_SCOPE)
    endif()
endfunction()

##############################################################################
##############################################################################
##############################################################################
set_property(GLOBAL PROPERTY NCBI_PTBPROP_ALLOWED_PROJECTS "")

macro(NCBI_internal_analyze_tree)
    if (NCBI_PTB_HAS_ROOT)
        message(FATAL_ERROR "Unexpected call to NCBI_internal_analyze_tree (${NCBI_CURRENT_SOURCE_DIR})")
        return()
    endif()
    set(NCBI_PTB_HAS_ROOT TRUE PARENT_SCOPE)
    set(NCBI_PTB_HAS_ROOT TRUE)
    foreach( _type IN ITEMS CONSOLEAPP GUIAPP STATIC SHARED CUSTOM)
        set_property(GLOBAL PROPERTY NCBI_PTBPROP_TOTAL_${_type} 0)
        set_property(GLOBAL PROPERTY NCBI_PTBPROP_COUNT_${_type} 0)
    endforeach()

    if( "${NCBI_PTBCFG_PROJECT_TARGETS}" STREQUAL "" AND
        "${NCBI_PTBCFG_PROJECT_TAGS}" STREQUAL "" AND
        "${NCBI_PTBCFG_PROJECT_LIST}" STREQUAL "" AND
        NOT DEFINED NCBI_EXTERNAL_TREE_ROOT)
        set(NCBI_PTB_NOFILTERS TRUE)
    endif()
    if (NCBI_PTBCFG_ENABLE_COLLECTOR AND NCBI_PTB_NOFILTERS AND NOT NCBI_PTBCFG_ALLOW_COMPOSITE)
        set(NCBI_PTBCFG_ENABLE_COLLECTOR FALSE)
        set(NCBI_PTBCFG_ENABLE_COLLECTOR FALSE PARENT_SCOPE)
    endif()

    if(NCBI_PTBCFG_ENABLE_COLLECTOR)
        if(NOT DEFINED NCBI_PTBCFG_KNOWN_FOLDERS OR "${NCBI_PTBCFG_KNOWN_FOLDERS}" STREQUAL "")
            file(GLOB _files LIST_DIRECTORIES TRUE "${NCBI_CURRENT_SOURCE_DIR}/*")
            foreach(_file IN LISTS _files)
                if(IS_DIRECTORY ${_file} AND EXISTS ${_file}/CMakeLists.txt)
                    get_filename_component(_basename ${_file} NAME)
                    list(APPEND NCBI_PTBCFG_KNOWN_FOLDERS ${_basename})
                endif()
            endforeach()
        endif()
        list(LENGTH NCBI_PTBCFG_KNOWN_FOLDERS _count)
        if(NOT ${_count} EQUAL 1)
            set(NCBI_PTB_THIS_SRC_ROOT ${NCBI_SRC_ROOT} PARENT_SCOPE)
            set(NCBI_PTB_THIS_SRC_ROOT ${NCBI_SRC_ROOT})
        endif()

        NCBI_util_elapsed(_elapsed)
        message("${_elapsed}: Analyzing source tree...")
        set_property(GLOBAL PROPERTY NCBI_PTBPROP_ALL_PROJECTS "")

        set(NCBI_PTBMODE_COLLECT_DEPS ON)
        set(_known ${NCBI_PTBCFG_KNOWN_FOLDERS})
        unset(NCBI_PTBCFG_KNOWN_FOLDERS)
        NCBI_add_subdirectory(${_known})
        set(NCBI_PTB_CALLBACK_ALL_PARSED TRUE)
        set(NCBI_PTBMODE_COLLECT_DEPS OFF)

        get_property(_allprojects     GLOBAL PROPERTY NCBI_PTBPROP_ALL_PROJECTS)
        get_property(_allowedprojects GLOBAL PROPERTY NCBI_PTBPROP_ALLOWED_PROJECTS)

        if(OFF)
            message("NCBI_PTBPROP_ALL_PROJECTS: ${_allprojects}")
            foreach(_prj IN LISTS _allprojects)
                get_property(_prjdeps GLOBAL PROPERTY NCBI_PTBPROP_DEPS_${_prj})
                message("NCBI_PTBPROP_DEPS_${_prj}: ${_prjdeps}")
            endforeach()
            message("NCBI_PTBPROP_ALLOWED_PROJECTS: ${_allowedprojects}")
        endif()

        if("${_allowedprojects}" STREQUAL "")
            message(FATAL_ERROR "List of projects is empty")
            return()
        endif()

        NCBI_util_elapsed(_elapsed)
        message("${_elapsed}: Collecting projects...")
        list(REMOVE_DUPLICATES _allowedprojects)
        foreach(_prj IN LISTS _allowedprojects)
            NCBI_internal_collect_dependencies(${_prj})
            get_property(_prjdeps GLOBAL PROPERTY NCBI_PTBPROP_DEPS_${_prj})
            get_property(_host GLOBAL PROPERTY NCBI_PTBPROP_HOST_${_prj})
            set(NCBI_PTB_ALLOWED_PROJECTS ${NCBI_PTB_ALLOWED_PROJECTS} ${_host} ${_prj} ${_prjdeps})
        endforeach()
        list(SORT NCBI_PTB_ALLOWED_PROJECTS)
        list(REMOVE_DUPLICATES NCBI_PTB_ALLOWED_PROJECTS)

        if(NCBI_PTBCFG_ALLOW_COMPOSITE)
            set(_allowedprojects ${NCBI_PTB_ALLOWED_PROJECTS})
            foreach(_prj IN LISTS _allowedprojects)
                NCBI_internal_collect_dependencies(${_prj})
                get_property(_prjdeps GLOBAL PROPERTY NCBI_PTBPROP_DEPS_${_prj})
                get_property(_host GLOBAL PROPERTY NCBI_PTBPROP_HOST_${_prj})
                set(NCBI_PTB_ALLOWED_PROJECTS ${NCBI_PTB_ALLOWED_PROJECTS} ${_host} ${_prj} ${_prjdeps})
            endforeach()
            list(SORT NCBI_PTB_ALLOWED_PROJECTS)
            list(REMOVE_DUPLICATES NCBI_PTB_ALLOWED_PROJECTS)
        endif()
        if(NOT NCBI_PTB_NOFILTERS)
            foreach(_prj IN LISTS NCBI_PTB_ALLOWED_PROJECTS)
                get_property(_dir GLOBAL PROPERTY NCBI_PTBPROP_DIR_${_prj})
                list(APPEND NCBI_PTB_ALLOWED_DIRS ${_dir})
            endforeach()
            list(SORT NCBI_PTB_ALLOWED_DIRS)
            list(REMOVE_DUPLICATES NCBI_PTB_ALLOWED_DIRS)
            set(NCBI_PTB_ALLOWED_DIRS ${NCBI_PTB_ALLOWED_DIRS} PARENT_SCOPE)
        endif()

        if(OFF)
            message("NCBI_PTB_ALLOWED_PROJECTS: ${NCBI_PTB_ALLOWED_PROJECTS}")
            foreach(_prj IN LISTS NCBI_PTB_ALLOWED_PROJECTS)
                get_property(_prjdeps GLOBAL PROPERTY NCBI_PTBPROP_DEPS_${_prj})
                message("NCBI_PTBPROP_DEPS_${_prj}: ${_prjdeps}")
            endforeach()
        endif()

        foreach(_prj IN LISTS NCBI_PTB_ALLOWED_PROJECTS)
            NCBI_internal_collect_requires(${_prj})
        endforeach()
        set(NCBI_PTB_CALLBACK_COLLECTED TRUE)
        foreach(_prj IN LISTS NCBI_PTB_ALLOWED_PROJECTS)
            if (NCBI_VERBOSE_ALLPROJECTS OR NCBI_VERBOSE_PROJECT_${_prj})
                NCBI_internal_print_project_info(${_prj})
            endif()
        endforeach()

        set(NCBI_PTB_ALLOWED_PROJECTS ${NCBI_PTB_ALLOWED_PROJECTS} PARENT_SCOPE)
    else()
        message("Source tree analysis skipped")
    endif()
    NCBI_util_elapsed(_elapsed)
    message("${_elapsed}: Configuring projects...")
    variable_watch(CMAKE_CURRENT_LIST_DIR NCBI_internal_end_of_config)
endmacro()

#############################################################################
function(NCBI_internal_end_of_config _variable _access _value)
    if(NOT "${_access}" STREQUAL "MODIFIED_ACCESS" OR NOT "${_value}" STREQUAL "")
        return()
    endif()
    set(NCBI_PTB_CALLBACK_ALL_ADDED TRUE)
    NCBI_internal_print_report("Processed" TOTAL)
    NCBI_internal_print_report("Added" COUNT)
    NCBI_util_elapsed(_elapsed)
    message("${_elapsed}: Done")
endfunction()

#############################################################################
function(NCBI_internal_collect_dependencies _project)
    get_property(_collected GLOBAL PROPERTY NCBI_PTBPROP_COLLECTED_DEPS)
    if( ${_project} IN_LIST _collected)
        return()
    endif()
    set_property(GLOBAL PROPERTY NCBI_PTBPROP_COLLECTED_DEPS ${_collected} ${_project})

    get_property(_prjdeps GLOBAL PROPERTY NCBI_PTBPROP_DIRECT_DEPS_${_project} SET)
    if (NOT _prjdeps)
        if(NOT TARGET ${_project})
            message("ERROR: project ${_project} not found")
        endif()
        return()
    endif()
    get_property(_prjdeps GLOBAL PROPERTY NCBI_PTBPROP_DIRECT_DEPS_${_project})
    foreach( _value IN LISTS _prjdeps)
        NCBI_internal_recur_collect_dependencies( ${_project} ${_value})
    endforeach()
    get_property(_prjdeps GLOBAL PROPERTY NCBI_PTBPROP_DEPS_${_project})
    foreach( _value IN LISTS _prjdeps)
        get_property(_host GLOBAL PROPERTY NCBI_PTBPROP_HOST_${_value})
        if ("${_host}" STREQUAL "")
            list(APPEND _deps ${_value})
        elseif( NOT "${_host}" STREQUAL "${_project}")
            list(APPEND _deps ${_host})
        endif()
    endforeach()
    if (NOT "${_deps}" STREQUAL "")
        list(SORT _deps)
        list(REMOVE_DUPLICATES _deps)
        list(REMOVE_ITEM _deps ${_project})
    endif()
    set_property(GLOBAL PROPERTY NCBI_PTBPROP_DEPS_${_project} "${_deps}")
endfunction()

##############################################################################
function(NCBI_internal_recur_collect_dependencies _project _dep)
    get_property(_prjdeps GLOBAL PROPERTY NCBI_PTBPROP_DEPS_${_project})
    get_property(_depdeps GLOBAL PROPERTY NCBI_PTBPROP_DIRECT_DEPS_${_dep} SET)
    if (NOT _depdeps)
        if(NOT TARGET ${_dep})
            message("ERROR: project ${_dep} not found (${_project} requires it)")
            set_property(GLOBAL PROPERTY NCBI_PTBPROP_DEPS_${_project} ${_dep})
        endif()
        return()
    endif()
    get_property(_depdeps GLOBAL PROPERTY NCBI_PTBPROP_DIRECT_DEPS_${_dep})
    foreach( _value IN LISTS _dep _depdeps)
        NCBI_internal_collect_dependencies(${_value}) 
        get_property(_valuedeps GLOBAL PROPERTY NCBI_PTBPROP_DEPS_${_value})
        set(_prjdeps ${_prjdeps} ${_value} ${_valuedeps})
    endforeach()
    if (NOT "${_prjdeps}" STREQUAL "")
        list(SORT _prjdeps)
        list(REMOVE_DUPLICATES _prjdeps)
        list(REMOVE_ITEM _prjdeps ${_project})
    endif()
    set_property(GLOBAL PROPERTY NCBI_PTBPROP_DEPS_${_project} ${_prjdeps})
endfunction()

##############################################################################
function(NCBI_internal_collect_requires _project)
    set(_implreq "")
    get_property(_y GLOBAL PROPERTY NCBI_PTBPROP_REQUIRES_${_project})
    list(APPEND _implreq "${_y}")
    get_property(_deps GLOBAL PROPERTY NCBI_PTBPROP_DEPS_${_project})
    if (NOT "${_deps}" STREQUAL "")
        list(REMOVE_DUPLICATES _deps)
        foreach(_dep IN LISTS _deps)
            get_property(_y GLOBAL PROPERTY NCBI_PTBPROP_REQUIRES_${_dep})
            list(APPEND _implreq "${_y}")
        endforeach()
    endif()
    if (NOT "${_implreq}" STREQUAL "")
        list(SORT _implreq)
        list(REMOVE_DUPLICATES _implreq)
        set_property(GLOBAL PROPERTY NCBI_PTBPROP_IMPLREQ_${_project} ${_implreq})
    endif()
endfunction()

##############################################################################
function(NCBI_internal_include)
    include(${ARGV0})
endfunction()

##############################################################################
function(NCBI_internal_collect_sources)
    set(_dir ${NCBI_CURRENT_SOURCE_DIR})
    if(NCBI_PTBMODE_PARTS)
        set(_prefix "Hosted Libraries\\${NCBI_PROJECT_PARTNAME}\\")
    else()
        set(_prefix "")
    endif()
    set(_c_ext ".c")
    set(_cpp_ext ".cpp;.cxx;.cc;.c++")
    set(_sources "")
    set(_nopch "")
    set(_ex "")

    if (NOT NCBI_PTBMODE_PARTS)
        if (${NCBI_${NCBI_PROJECT}_TYPE} STREQUAL "SHARED")
            NCBI_util_get_value(DLLENTRY _entry)
            if (NOT "${_entry}" STREQUAL "")
                list(APPEND _ex ${_entry})
            endif()
        endif()
        if (${NCBI_${NCBI_PROJECT}_TYPE} STREQUAL "GUIAPP")
            NCBI_util_get_value(GUIENTRY _entry)
            if (NOT "${_entry}" STREQUAL "")
                list(APPEND _ex ${_entry})
            endif()
        endif()
    endif()

    foreach(_file IN LISTS NCBI_${NCBI_PROJECT}_SOURCES _ex)
        if(EXISTS ${_dir}/${_file} AND NOT IS_DIRECTORY ${_dir}/${_file})
            set(_file "${_dir}/${_file}")
        else()
            foreach(_ext IN LISTS _c_ext _cpp_ext)
                if(EXISTS ${_dir}/${_file}${_ext})
                    set(_file "${_dir}/${_file}${_ext}")
                    break()
                endif()
            endforeach()
        endif()
        list(APPEND _sources "${_file}")
    endforeach()

    foreach(_file IN LISTS NCBI_${NCBI_PROJECT}_GENERATED_SOURCES)
        if(NOT IS_ABSOLUTE ${_file})
            set(_file "${_dir}/${_file}")
        endif()
        list(APPEND _sources "${_file}")
        set_source_files_properties(${_file} PROPERTIES GENERATED TRUE)
    endforeach()

    foreach(_file IN LISTS NCBI_${NCBI_PROJECT}_NOPCH)
        if(EXISTS ${_dir}/${_file} AND NOT IS_DIRECTORY ${_dir}/${_file})
            set(_file "${_dir}/${_file}")
        else()
            foreach(_ext IN LISTS _c_ext _cpp_ext)
                if(EXISTS ${_dir}/${_file}${_ext})
                    set(_file "${_dir}/${_file}${_ext}")
                    break()
                endif()
            endforeach()
        endif()
        list(APPEND _nopch   "${_file}")
    endforeach()
    foreach(_file IN LISTS _sources)
        get_filename_component(_fext ${_file} EXT)
        foreach(_ext IN LISTS _c_ext)
            if("${_fext}" STREQUAL "${_ext}")
                list(APPEND _nopch "${_file}")
            endif()
        endforeach()
    endforeach()
    if(NOT "${_nopch}" STREQUAL "")
        list(REMOVE_DUPLICATES _nopch)
    endif()

    if(NCBI_VERBOSE_ALLPROJECTS OR NCBI_VERBOSE_PROJECT_${NCBI_PROJECT})
        message("create source group  ${_prefix}Source Files")
        message("${_sources}")
    endif()
    source_group("${_prefix}Source Files"   FILES ${_sources})
    set(NCBITMP_PROJECT_SOURCES ${NCBITMP_PROJECT_SOURCES} ${_sources} PARENT_SCOPE)
    set(NCBITMP_PROJECT_NOPCH   ${NCBITMP_PROJECT_NOPCH}   ${_nopch}   PARENT_SCOPE)
endfunction()

##############################################################################
function(NCBI_internal_collect_headers)

    file(RELATIVE_PATH _rel "${NCBI_SRC_ROOT}" "${NCBI_CURRENT_SOURCE_DIR}")
    if (NOT "${NCBI_INC_ROOT}" STREQUAL "${NCBI_SRC_ROOT}")
        set(_inc_dir ${NCBI_INC_ROOT}/${_rel})
    else()
        set(_inc_dir "")
    endif()
    if(NCBI_PTBMODE_PARTS)
        set(_prefix "Hosted Libraries\\${NCBI_PROJECT_PARTNAME}\\")
    else()
        set(_prefix "")
    endif()
    NCBI_util_get_value(HEADERS _headers)

    if (MSVC_IDE OR XCODE)
        set(_priv "")
        set(_pub "")
        set(_inl "")
        if ( NOT "${_headers}" STREQUAL "")
            foreach(_mask IN LISTS _headers)
                file(GLOB _files LIST_DIRECTORIES false "${NCBI_CURRENT_SOURCE_DIR}/${_mask}")
                set(_priv ${_priv} ${_files})
                if (NOT "${_inc_dir}" STREQUAL "")
                    if (${_mask} MATCHES "[.]inl$")
                        file(GLOB _files LIST_DIRECTORIES false "${_inc_dir}/${_mask}")
                        set(_inl ${_inl} ${_files})
                    else()
                        file(GLOB _files LIST_DIRECTORIES false "${_inc_dir}/${_mask}")
                        set(_pub ${_pub} ${_files})
                    endif()
                endif()
            endforeach()

            if ( NOT "${_priv}" STREQUAL "")
                source_group("${_prefix}Private Headers" FILES ${_priv})
            endif()
            if ( NOT "${_pub}" STREQUAL "")
                source_group("${_prefix}Header Files"    FILES ${_pub})
            endif()
            if ( NOT "${_inl}" STREQUAL "")
                source_group("${_prefix}Inline Files"    FILES ${_inl})
            endif()
        endif()
        set(NCBITMP_PROJECT_HEADERS ${NCBITMP_PROJECT_HEADERS} ${_priv} ${_pub} ${_inl} PARENT_SCOPE)
    else()
        set(NCBITMP_PROJECT_HEADERS "" PARENT_SCOPE)
    endif()
endfunction()

##############################################################################
function(NCBI_internal_add_resources) 
    if (WIN32)
        if (${NCBI_${NCBI_PROJECT}_TYPE} STREQUAL "CONSOLEAPP" OR ${NCBI_${NCBI_PROJECT}_TYPE} STREQUAL "GUIAPP")
            NCBI_util_get_value(RESOURCES _res)
        else()
            if (DEFINED NCBI_${NCBI_PROJECT}_RESOURCES)
                set(_res ${NCBI_${NCBI_PROJECT}_RESOURCES})
            else()
                set(_res "")
            endif()
        endif()

        if(NCBI_PTBMODE_PARTS)
            set(_prefix "Hosted Libraries\\${NCBI_PROJECT_PARTNAME}\\")
        else()
            set(_prefix "")
        endif()
        if ( NOT "${_res}" STREQUAL "")
            source_group("${_prefix}Resource Files" FILES ${_res})
        endif()
        set(NCBITMP_PROJECT_RESOURCES ${_res} PARENT_SCOPE)
    else()
        set(NCBITMP_PROJECT_RESOURCES "" PARENT_SCOPE)
    endif()
endfunction()

##############################################################################
function(NCBI_internal_collect_dataspec)
    if (NOT DEFINED NCBI_${NCBI_PROJECT}_DATASPEC)
        return()
    endif()

    if(NCBI_PTBMODE_PARTS)
        set(_prefix "Hosted Libraries\\${NCBI_PROJECT_PARTNAME}\\")
    else()
        set(_prefix "")
    endif()

    foreach(_dataspec IN LISTS NCBI_${NCBI_PROJECT}_DATASPEC)
        if (EXISTS ${NCBI_CURRENT_SOURCE_DIR}/${_dataspec})
            get_filename_component(_ext ${_dataspec} EXT)
            set(_input DATASPEC ${NCBI_CURRENT_SOURCE_DIR}/${_dataspec} REQUIRES ${NCBITMP_REQUIRE} ${NCBITMP_COMPONENTS} RETURN _output)
            string(TOLOWER ${_ext} _ext)
            set( NCBI_PTB_CALLBACK_DATASPEC${_ext} ${_input})
            cmake_parse_arguments(DT "" "DATASPEC" "SOURCES;HEADERS;INCLUDE" ${_output})
            set(_specfiles ${_specfiles} ${DT_DATASPEC})
            set(_srcfiles ${_srcfiles} ${DT_SOURCES})
            set(_incfiles ${_incfiles} ${DT_HEADERS})
        else()
            message(SEND_ERROR "file not found: ${NCBI_CURRENT_SOURCE_DIR}/${_dataspec}")
        endif()
    endforeach()

    set_source_files_properties(${_srcfiles} ${_incfiles} PROPERTIES GENERATED TRUE)
    source_group("${_prefix}Source Files"   FILES ${_srcfiles})
    set(NCBITMP_PROJECT_SOURCES ${NCBITMP_PROJECT_SOURCES} ${_srcfiles} PARENT_SCOPE)
    source_group("${_prefix}Header Files"   FILES ${_incfiles})
    set(NCBITMP_PROJECT_HEADERS ${NCBITMP_PROJECT_HEADERS} ${_incfiles} PARENT_SCOPE)
    source_group("${_prefix}DataSpec Files" FILES ${_specfiles})
    set(NCBITMP_PROJECT_DATASPEC ${NCBITMP_PROJECT_DATASPEC} ${_specfiles} PARENT_SCOPE)
endfunction()

##############################################################################
function(NCBI_internal_add_dataspec)
    if (NOT DEFINED NCBITMP_PROJECT_DATASPEC)
        return()
    endif()
    foreach(_dataspec IN LISTS NCBITMP_PROJECT_DATASPEC)
        get_filename_component(_ext ${_dataspec} EXT)
        set(_input GENERATE DATASPEC ${_dataspec} REQUIRES ${NCBITMP_REQUIRE} ${NCBITMP_COMPONENTS} RETURN _output)
        string(TOLOWER ${_ext} _ext)
        set( NCBI_PTB_CALLBACK_DATASPEC${_ext} ${_input})
        cmake_parse_arguments(DT "" "DATASPEC" "SOURCES;HEADERS;INCLUDE" ${_output})
        if(NOT "${DT_INCLUDE}" STREQUAL "")
            set(NCBITMP_INCLUDES ${NCBITMP_INCLUDES} ${DT_INCLUDE} PARENT_SCOPE)
        endif()
    endforeach()
endfunction()

##############################################################################
function(NCBI_internal_define_precompiled_header_usage)

    NCBI_util_get_value(USEPCH _usepch)
    NCBI_util_get_value(PCH _pch)
    NCBI_util_get_value(PCH_DEFINE _pchdef)

if(NCBI_VERBOSE_ALLPROJECTS OR NCBI_VERBOSE_PROJECT_${NCBI_PROJECT})
    message("_usepch ${_usepch}:  prj=${NCBI_${NCBI_PROJECT}_USEPCH} dir=${NCBI__USEPCH} def=${NCBI_DEFAULT_USEPCH}")
    message("_pch ${_pch}:  prj=${NCBI_${NCBI_PROJECT}_PCH} dir=${NCBI__PCH} def=${NCBI_DEFAULT_PCH}")
    message("_pchdef ${_pchdef}")
endif()

    if (NOT DEFINED NCBITMP_PROJECT_SOURCES)
        set(_usepch OFF)
    endif()

    if (_usepch)
        if (MSVC)
            set_target_properties(${NCBI_PROJECT} PROPERTIES COMPILE_FLAGS "/Yu${_pch}")
            set(_files ${NCBITMP_PROJECT_SOURCES})
            if (DEFINED NCBITMP_PROJECT_NOPCH)
                foreach(_file IN LISTS NCBITMP_PROJECT_NOPCH)
                    list(REMOVE_ITEM _files ${_file})
                    set_source_files_properties(${_file} PROPERTIES COMPILE_FLAGS "/Y-")
                endforeach()
            endif()

            if ("${_files}" STREQUAL "")
                return()
            endif()
            list(GET _files 0 _pchfile)
            get_filename_component(_pchname ${_pchfile} NAME)
            foreach(_file IN LISTS _files)
                get_filename_component(_name ${_file} NAME)
                if (${_name} STRLESS ${_pchname})
                    set(_pchname ${_name})
                    set(_pchfile ${_file})
                endif()
                set_source_files_properties(${_file} PROPERTIES COMPILE_DEFINITIONS ${_pchdef})
            endforeach()
            set_source_files_properties(${_pchfile} PROPERTIES COMPILE_FLAGS "/Yc${_pch}")

        elseif (XCODE)

            if (EXISTS ${NCBI_CURRENT_SOURCE_DIR}/${_pch})
                set(_pch ${NCBI_CURRENT_SOURCE_DIR}/${_pch})
            elseif (EXISTS ${NCBI_INC_ROOT}/${_pch})
                set(_pch ${NCBI_INC_ROOT}/${_pch})
            else()
                file(RELATIVE_PATH _rel "${NCBI_SRC_ROOT}" "${NCBI_CURRENT_SOURCE_DIR}")
                if (EXISTS "${NCBI_INC_ROOT}/${_rel}/${_pch}")
                    set(_pch "${NCBI_INC_ROOT}/${_rel}/${_pch}")
                else()
#                    message(WARNING "ERROR: in project ${NCBI_CURRENT_SOURCE_DIR}/${NCBI_PROJECT}, precompiled header ${_pch} was not found.")
                    set(_usepch NO)
                endif()
            endif()
            if (_usepch)
                set_target_properties(${NCBI_PROJECT} PROPERTIES XCODE_ATTRIBUTE_GCC_PRECOMPILE_PREFIX_HEADER "YES")
                set_target_properties(${NCBI_PROJECT} PROPERTIES XCODE_ATTRIBUTE_GCC_PREFIX_HEADER "${_pch}")
            endif()
        endif()
    endif()
endfunction()

##############################################################################
function(NCBI_internal_install_component_files _comp)
    if (NOT DEFINED NCBI_COMPONENT_${_comp}_BINPATH)
        return()
    endif()

    set(_rt ${NCBI_CONFIGURATION_RUNTIMELIB})
    foreach(_cfg IN LISTS NCBI_CONFIGURATION_TYPES)
        if (DEFINED NCBI_COMPONENT_${_comp}_BINPATH_${_cfg}${_rt})
            set(_src ${NCBI_COMPONENT_${_comp}_BINPATH_${_cfg}${_rt}})
        elseif (DEFINED NCBI_COMPONENT_${_comp}_BINPATH_${_cfg})
            set(_src ${NCBI_COMPONENT_${_comp}_BINPATH_${_cfg}})
        elseif (DEFINED NCBI_COMPONENT_${_comp}_BINPATH)
            if (IS_DIRECTORY ${NCBI_COMPONENT_${_comp}_BINPATH}/${_cfg}${_rt})
                set(_src ${NCBI_COMPONENT_${_comp}_BINPATH}/${_cfg}${_rt})
            elseif (IS_DIRECTORY ${NCBI_COMPONENT_${_comp}_BINPATH}/${_cfg})
                set(_src ${NCBI_COMPONENT_${_comp}_BINPATH}/${_cfg})
            else()
                set(_src ${NCBI_COMPONENT_${_comp}_BINPATH})
            endif()
        else()
            continue()
        endif()
        if (IS_DIRECTORY ${_src})
            file(GLOB _files LIST_DIRECTORIES false "${_src}/*${CMAKE_SHARED_LIBRARY_SUFFIX}")
            foreach(_file IN LISTS _files)
#message("============ COPY ${_file}  DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${_cfg}")
                file(COPY ${_file}  DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${_cfg})
            endforeach()
        endif()
    endforeach()
endfunction()

##############################################################################
macro(NCBI_internal_process_project_requires)
    set(NCBITMP_REQUIRE_NOTFOUND "")
    if(NCBI_PTBMODE_PARTS)
        set(_all ${NCBI__REQUIRES} ${NCBI_${NCBI_PROJECT}_REQUIRES})
    else()
        set(_all ${NCBI__REQUIRES} ${NCBI_${NCBI_PROJECT}_REQUIRES} ${NCBITMP_PROJECT_REQUIRES})
    endif()
    if (NOT "${_all}" STREQUAL "")
        list(REMOVE_DUPLICATES _all)
    endif()

    set(NCBITMP_REQUIRE ${_all})
    if(NCBI_PTBMODE_COLLECT_DEPS)
        set_property(GLOBAL PROPERTY NCBI_PTBPROP_REQUIRES_${NCBI_PROJECT} ${_all})
    endif()

    foreach(_req IN LISTS _all)
        NCBI_util_parse_sign(${_req} _value _negate)
        if(${_value} IN_LIST NCBI_ALL_LEGACY)
            if (NOT NCBI_PTBMODE_COLLECT_DEPS)
                message(SEND_ERROR "${NCBI_PROJECT} (${NCBI_CURRENT_SOURCE_DIR}) component name ${_value} is deprecated, use ${NCBI_COMPONENT_${_value}_FOUND} instead")
            endif()
            set(_value ${NCBI_COMPONENT_${_value}_FOUND})
        endif()
        if (${_value} OR NCBI_REQUIRE_${_value}_FOUND OR NCBI_COMPONENT_${_value}_FOUND)
            if (_negate)
                set(NCBITMP_REQUIRE_NOTFOUND ${NCBITMP_REQUIRE_NOTFOUND} ${_req})
            else()
#                set(NCBITMP_INCLUDES ${NCBITMP_INCLUDES} ${NCBI_COMPONENT_${_value}_INCLUDE})
                set(NCBITMP_INCLUDES_SYSTEM ${NCBITMP_INCLUDES_SYSTEM} ${NCBI_COMPONENT_${_value}_INCLUDE})
                set(NCBITMP_DEFINES  ${NCBITMP_DEFINES}  ${NCBI_COMPONENT_${_value}_DEFINES})
                set(NCBITMP_EXTLIB   ${NCBITMP_EXTLIB}   ${NCBI_COMPONENT_${_value}_LIBS})
                foreach(_lib IN LISTS NCBI_COMPONENT_${_value}_NCBILIB)
                    if(NOT ${_lib} STREQUAL ${NCBI_${NCBI_PROJECT}_OUTPUT})
                        set(NCBITMP_NCBILIB  ${NCBITMP_NCBILIB}  ${_lib})
                    endif()
                endforeach()
                if (WIN32 AND NOT NCBI_PTBMODE_COLLECT_DEPS)
                    NCBI_internal_install_component_files(${_value})
                endif()
            endif()
        else()
            if (_negate)
# no-no, this is a mistake
#        set(NCBITMP_INCLUDES ${NCBITMP_INCLUDES} ${NCBI_COMPONENT_${_value}_INCLUDE})
#        set(NCBITMP_DEFINES  ${NCBITMP_DEFINES}  ${NCBI_COMPONENT_${_value}_DEFINES})
#        set(NCBITMP_EXTLIB     ${NCBITMP_EXTLIB}     ${NCBI_COMPONENT_${_value}_LIBS})
            else()
                set(NCBITMP_REQUIRE_NOTFOUND ${NCBITMP_REQUIRE_NOTFOUND} ${_req})
            endif()
        endif()     
    endforeach()

    if (NOT NCBI_PTBMODE_COLLECT_DEPS AND NOT ${NCBI_${NCBI_PROJECT}_TYPE} STREQUAL "STATIC")
        get_property(_all GLOBAL PROPERTY NCBI_PTBPROP_IMPLREQ_${NCBI_PROJECT})
        foreach(_req IN LISTS _all)
            NCBI_util_parse_sign(${_req} _value _negate)
            if (${_value} OR NCBI_REQUIRE_${_value}_FOUND OR NCBI_COMPONENT_${_value}_FOUND)
                if (_negate)
                    set(NCBITMP_REQUIRE_NOTFOUND ${NCBITMP_REQUIRE_NOTFOUND} ${_req})
                endif()
            else()
                if (NOT _negate)
                    set(NCBITMP_REQUIRE_NOTFOUND ${NCBITMP_REQUIRE_NOTFOUND} ${_req})
                endif()
            endif()     
        endforeach()
    endif()

    if (NOT "${NCBITMP_REQUIRE_NOTFOUND}" STREQUAL "")
        list(REMOVE_DUPLICATES NCBITMP_REQUIRE_NOTFOUND)
    endif()
endmacro()

##############################################################################
macro(NCBI_internal_process_project_components)
    set(NCBITMP_COMPONENT_NOTFOUND "")
    if(NCBI_PTBMODE_PARTS)
        set(_all ${NCBI__COMPONENTS} ${NCBI_${NCBI_PROJECT}_COMPONENTS})
    else()
        set(_all ${NCBI__COMPONENTS} ${NCBI_${NCBI_PROJECT}_COMPONENTS} ${NCBITMP_PROJECT_COMPONENTS})
    endif()
    if (NOT "${_all}" STREQUAL "")
        list(REMOVE_DUPLICATES _all)
    endif()

    set(NCBITMP_COMPONENTS ${_all})
    if(NCBI_PTBMODE_COLLECT_DEPS)
        set_property(GLOBAL PROPERTY NCBI_PTBPROP_COMPONENTS_${NCBI_PROJECT} ${_all})
    endif()

    foreach(_value IN LISTS _all)
        if(${_value} IN_LIST NCBI_ALL_LEGACY)
            if (NOT NCBI_PTBMODE_COLLECT_DEPS)
                message(SEND_ERROR "${NCBI_PROJECT} (${NCBI_CURRENT_SOURCE_DIR}) component name ${_value} is deprecated, use ${NCBI_COMPONENT_${_value}_FOUND} instead")
            endif()
            set(_value ${NCBI_COMPONENT_${_value}_FOUND})
        endif()
        if (${_value} OR NCBI_REQUIRE_${_value}_FOUND OR NCBI_COMPONENT_${_value}_FOUND)
#            set(NCBITMP_INCLUDES ${NCBITMP_INCLUDES} ${NCBI_COMPONENT_${_value}_INCLUDE})
            set(NCBITMP_INCLUDES_SYSTEM ${NCBITMP_INCLUDES_SYSTEM} ${NCBI_COMPONENT_${_value}_INCLUDE})
            set(NCBITMP_DEFINES  ${NCBITMP_DEFINES}  ${NCBI_COMPONENT_${_value}_DEFINES})
            set(NCBITMP_EXTLIB   ${NCBITMP_EXTLIB}   ${NCBI_COMPONENT_${_value}_LIBS})
            foreach(_lib IN LISTS NCBI_COMPONENT_${_value}_NCBILIB)
                if(NOT ${_lib} STREQUAL ${NCBI_${NCBI_PROJECT}_OUTPUT})
                    set(NCBITMP_NCBILIB  ${NCBITMP_NCBILIB}  ${_lib})
                endif()
            endforeach()
            if (WIN32 AND NOT NCBI_PTBMODE_COLLECT_DEPS)
                NCBI_internal_install_component_files(${_value})
            endif()
        else()
            set(NCBITMP_COMPONENT_NOTFOUND ${NCBITMP_COMPONENT_NOTFOUND} ${_value})
        endif()
    endforeach()
endmacro()

##############################################################################
function(NCBI_internal_collect_parts _result)
    set(_hostproject ${NCBI_PROJECT})
    set(_hostdir ${NCBI_CURRENT_SOURCE_DIR})
# verify that all parts can be found
    foreach(_part IN LISTS NCBI_${_hostproject}_PARTS)
        set(_filepath ${NCBI_SRC_ROOT}/${_part})
        get_filename_component(_path ${_filepath} DIRECTORY)
        if(NOT EXISTS ${_path}/CMakeLists.txt)
            if(NCBI_VERBOSE_ALLPROJECTS OR NCBI_VERBOSE_PROJECT_${NCBI_PROJECT})
                message("WARNING: Project part ${_part} not found: ${NCBI_PROJECT} (${NCBI_CURRENT_SOURCE_DIR}): ")
            endif()
            set(${_result} FALSE PARENT_SCOPE)
            return()
        endif()
    endforeach()

    set(NCBI_PTBMODE_PARTS ON)
    foreach(_part IN LISTS NCBI_${_hostproject}_PARTS)
        set(_filepath ${NCBI_SRC_ROOT}/${_part})
        get_filename_component(_path ${_filepath} DIRECTORY)
        get_filename_component(_lib ${_filepath} NAME)

        unset(NCBI_PROJECT)
        unset(NCBI_PROJECT_ID)
        unset(NCBI__USEPCH)
        unset(NCBI__REQUIRES)
        unset(NCBI__COMPONENTS)
        unset(NCBI__INCLUDES)
        unset(NCBI__DEFINES)
        unset(NCBI__NCBILIB)
        unset(NCBI__EXTLIB)

        file(RELATIVE_PATH _relpath ${NCBI_SRC_ROOT} ${_path})
        string(REPLACE "/" ";" _dirlist ${_relpath})
        set(NCBI_CURRENT_SOURCE_DIR ${NCBI_SRC_ROOT})
        foreach(_dir IN LISTS _dirlist)
            set(NCBI_CURRENT_SOURCE_DIR ${NCBI_CURRENT_SOURCE_DIR}/${_dir})
            if(EXISTS ${NCBI_CURRENT_SOURCE_DIR}/CMakeLists.txt)
                include(${NCBI_CURRENT_SOURCE_DIR}/CMakeLists.txt)
            endif()
        endforeach()
        set(NCBI_CURRENT_SOURCE_DIR ${_path})

        if (EXISTS ${_path}/CMakeLists.${_lib}.lib.txt)
            include(${_path}/CMakeLists.${_lib}.lib.txt)
        elseif (EXISTS ${_path}/CMakeLists.${_lib}.asn.txt)
            include(${_path}/CMakeLists.${_lib}.asn.txt)
        elseif (EXISTS ${_path}/CMakeLists.${_lib}.txt)
            include(${_path}/CMakeLists.${_lib}.txt)
        else()
            message("ERROR: Project part ${_part} not found: ${NCBI_PROJECT} (${NCBI_CURRENT_SOURCE_DIR}): ")
            set(${_result} FALSE PARENT_SCOPE)
            return()
        endif()
    endforeach()

    set(NCBITMP_PROJECT_PART_IDS    ${NCBITMP_PROJECT_PART_IDS}   PARENT_SCOPE)
    set(NCBITMP_PROJECT_PARTS       ${NCBITMP_PROJECT_PARTS}      PARENT_SCOPE)
    set(NCBITMP_PROJECT_REQUIRES    ${NCBITMP_PROJECT_REQUIRES}   PARENT_SCOPE)
    set(NCBITMP_PROJECT_COMPONENTS  ${NCBITMP_PROJECT_COMPONENTS} PARENT_SCOPE)
    set(NCBITMP_PROJECT_INCLUDES    ${NCBITMP_PROJECT_INCLUDES}   PARENT_SCOPE)
    set(NCBITMP_PROJECT_DEFINES     ${NCBITMP_PROJECT_DEFINES}    PARENT_SCOPE)
    set(NCBITMP_PROJECT_NCBILIB     ${NCBITMP_PROJECT_NCBILIB}    PARENT_SCOPE)
    set(NCBITMP_PROJECT_EXTLIB      ${NCBITMP_PROJECT_EXTLIB}     PARENT_SCOPE)
    set(NCBITMP_PROJECT_SOURCES     ${NCBITMP_PROJECT_SOURCES}    PARENT_SCOPE)
    set(NCBITMP_PROJECT_NOPCH       ${NCBITMP_PROJECT_NOPCH}      PARENT_SCOPE)
    set(NCBITMP_PROJECT_DATASPEC    ${NCBITMP_PROJECT_DATASPEC}   PARENT_SCOPE)
    set(NCBITMP_PROJECT_HEADERS     ${NCBITMP_PROJECT_HEADERS}    PARENT_SCOPE)
    set(${_result} TRUE PARENT_SCOPE)
    return()
endfunction()

##############################################################################
macro(NCBI_internal_process_parts _result)

    set(NCBITMP_PROJECT_PART_IDS "")
    set(NCBITMP_PROJECT_PARTS "")
    NCBI_internal_collect_parts(_result)

    if(_result)
        if (NCBI_PTBMODE_COLLECT_DEPS OR NOT NCBI_PTBCFG_ENABLE_COLLECTOR)
#set_property(GLOBAL PROPERTY NCBI_PTBPROP_PARTS_${NCBI_PROJECT_ID} ${NCBITMP_PROJECT_PART_IDS})
            foreach(_part IN LISTS NCBITMP_PROJECT_PART_IDS)
                set_property(GLOBAL PROPERTY NCBI_PTBPROP_HOSTID_${_part} ${NCBI_PROJECT_ID})
            endforeach()
            foreach(_part IN LISTS NCBITMP_PROJECT_PARTS NCBI_${NCBI_PROJECT}_VIRTPARTS)
                if (NOT "${_part}" STREQUAL ${NCBI_PROJECT})
                    set_property(GLOBAL PROPERTY NCBI_PTBPROP_HOST_${_part} ${NCBI_PROJECT})
                endif()
            endforeach()
        endif()
    endif()
endmacro()

##############################################################################
function(NCBI_internal_process_interface_libraries _lib)
    if (NOT TARGET ${_lib})
        return()
    endif()
    get_target_property(_deps ${_lib} INTERFACE_LINK_LIBRARIES)
    if ( NOT "${_deps}" STREQUAL "")
        set(_value "")
        foreach(_prj IN LISTS _deps)
            get_property(_local GLOBAL PROPERTY NCBI_PTBPROP_LOCAL_${_prj})
            if ("${_local}" STREQUAL "" OR NOT ${_local} IN_LIST NCBI_PTB_ALLOWED_PROJECTS)
                set(_value ${_value} ${_prj})
                NCBI_internal_process_interface_libraries(${_prj})
            else()
                set(_value ${_value} ${_local})
            endif()
        endforeach()
        set_target_properties(${_lib} PROPERTIES INTERFACE_LINK_LIBRARIES "${_value}")
    endif()
endfunction()

##############################################################################
function(NCBI_internal_verify_ncbilibs)
    set(_res "")
    set(_exclude "")
    foreach(_prj IN LISTS NCBITMP_NCBILIB)
        NCBI_util_parse_sign(${_prj} _value _negate)
        list(APPEND _res ${_value})
        if (_negate)
            list(APPEND _exclude ${_value})
        endif()
    endforeach()
    foreach(_prj IN LISTS _exclude)
        list(REMOVE_ITEM _res ${_prj})
    endforeach()
    set(NCBITMP_NCBILIB ${_res} PARENT_SCOPE)
endfunction()

##############################################################################
function(NCBI_internal_verify_libs)
    set(_optimize NO)
    if (WIN32 AND NCBI_PTBCFG_ENABLE_COLLECTOR
        AND NOT NCBI_PTBMODE_COLLECT_DEPS
        AND NOT DEFINED NCBI_EXTERNAL_TREE_ROOT
        AND NOT DEFINED NCBI_PTBCFG_DOINSTALL)
        if (${NCBI_${NCBI_PROJECT}_TYPE} STREQUAL "STATIC")
#            set(_ncbilib ${NCBITMP_NCBILIB})
            get_property(_ncbilib GLOBAL PROPERTY NCBI_PTBPROP_DEPS_${NCBI_PROJECT})
            set(_optimize YES)
        else()
            get_property(_ncbilib GLOBAL PROPERTY NCBI_PTBPROP_DEPS_${NCBI_PROJECT})
            if ("${_ncbilib}" STREQUAL "")
                set(_ncbilib ${NCBITMP_NCBILIB})
            endif()
        endif()
    else()
        set(_ncbilib ${NCBITMP_NCBILIB})
    endif()
    if(NCBI_VERBOSE_ALLPROJECTS OR NCBI_VERBOSE_PROJECT_${NCBI_PROJECT})
        message("NCBI_internal_verify_libs ${NCBI_PROJECT_ID}:  on enter = ${_ncbilib}")
    endif()
    set(_value "")
    if ( NOT "${_ncbilib}" STREQUAL "")
        list(REMOVE_DUPLICATES _ncbilib)
        foreach(_prj IN LISTS _ncbilib)
            get_property(_host GLOBAL PROPERTY NCBI_PTBPROP_HOST_${_prj})
            if ("${_host}" STREQUAL "")
                if (_optimize)
                    get_property(_hasspec GLOBAL PROPERTY NCBI_PTBPROP_DATASPEC_${_prj})
                    if (_hasspec)
                        set(_value ${_value} ${_prj})
                    endif()
                else()
                    set(_value ${_value} ${_prj})
                endif()
            else()
                set(_value ${_value} ${_host})
            endif()
        endforeach()
    endif()
    if ( NOT "${_value}" STREQUAL "")
        list(REMOVE_DUPLICATES _value)
        list(REMOVE_ITEM _value ${NCBI_PROJECT})
        set(_ncbilib ${_value})
    endif()

    if ( NOT "${_ncbilib}" STREQUAL "" AND DEFINED NCBI_EXTERNAL_TREE_ROOT)
        set(_value "")
        foreach(_prj IN LISTS _ncbilib)
            get_property(_local GLOBAL PROPERTY NCBI_PTBPROP_LOCAL_${_prj})
            if ("${_local}" STREQUAL "" OR NOT ${_local} IN_LIST NCBI_PTB_ALLOWED_PROJECTS)
                set(_value ${_value} ${_prj})
                NCBI_internal_process_interface_libraries(${_prj})
            else()
                set(_value ${_value} ${_local})
            endif()
        endforeach()
    endif()

    if (NOT NCBI_PTBMODE_COLLECT_DEPS)
        set(_tk_libs "${_value}")
        set(_value "")
        foreach(_tk_lib IN LISTS _tk_libs)
            if(${_tk_lib} STREQUAL "general")
                set(_value ${_value} \$<1:general>)
            else()
                set(_value ${_value} ${_tk_lib})
            endif()
        endforeach()

        get_property(_allprojects     GLOBAL PROPERTY NCBI_PTBPROP_ALL_PROJECTS)
        set(NCBITMP_TARGET_NOTFOUND "")
        get_property(_tk_libs GLOBAL PROPERTY NCBI_PTBPROP_DEPS_${NCBI_PROJECT})
        if(NOT "${_tk_libs}" STREQUAL "")
            foreach(_tk_lib IN LISTS _tk_libs)
                if(NOT TARGET ${_tk_lib} AND NOT ${_tk_lib} IN_LIST _allprojects)
                    list(APPEND NCBITMP_TARGET_NOTFOUND ${_tk_lib})
                endif()
            endforeach()
        endif()
    endif()

    if(NCBI_VERBOSE_ALLPROJECTS OR NCBI_VERBOSE_PROJECT_${NCBI_PROJECT})
        message("NCBI_internal_verify_libs ${NCBI_PROJECT_ID}:  on exit = ${_value}")
    endif()
    list(REMOVE_DUPLICATES _value)
    set(NCBITMP_NCBILIB ${_value} PARENT_SCOPE)
    set(NCBITMP_TARGET_NOTFOUND ${NCBITMP_TARGET_NOTFOUND} PARENT_SCOPE)
endfunction()

##############################################################################
function(NCBI_internal_process_project_filters _result)

    if(NOT "${NCBI_PTBCFG_PROJECT_TARGETS}" STREQUAL "" AND NOT "${NCBI_PROJECT}" STREQUAL "")
        foreach(_prj IN LISTS NCBI_PTBCFG_PROJECT_TARGETS)
            if("${_prj}" STREQUAL "")
                continue()
            endif()
            NCBI_util_parse_sign( ${_prj} _value _negate)
            if (${NCBI_PROJECT} STREQUAL ${_value})
                if(_negate)
                    set(${_result} FALSE PARENT_SCOPE)
                else()
                    set(${_result} TRUE PARENT_SCOPE)
                endif()
                return()
            endif()
        endforeach()
    endif()

    if(NOT "${NCBI_PTBCFG_PROJECT_TAGS}" STREQUAL "" AND NOT "${NCBI_PROJECT}" STREQUAL "")
        set(_alltags ${NCBI__PROJTAG} ${NCBI_${NCBI_PROJECT}_PROJTAG})
        if("${NCBI_PTBCFG_PROJECT_TAGS}" STREQUAL "-")
            if(NOT "${_alltags}" STREQUAL "")
                set(${_result} FALSE PARENT_SCOPE)
                return()
            endif()
        endif()
        set(_is_good FALSE)
        set(_hasp FALSE)
        foreach(_tag IN LISTS NCBI_PTBCFG_PROJECT_TAGS)
            if("${_tag}" STREQUAL "")
                continue()
            endif()
            if(${_tag} STREQUAL "*")
                set(_is_good TRUE)
                continue()
            endif()
            NCBI_util_parse_sign( ${_tag} _value _negate)
            if(_negate)
                if( ${_value} IN_LIST _alltags)
                    set(${_result} FALSE PARENT_SCOPE)
                    return()
                endif()
            else()
                set(_hasp TRUE)
                if( ${_value} IN_LIST _alltags)
                    set(_is_good TRUE)
                endif()
            endif()
        endforeach()
        if(NOT _is_good AND _hasp)
            set(${_result} FALSE PARENT_SCOPE)
            return()
        endif()
    endif()

    if(NOT "${NCBI_PTBCFG_PROJECT_LIST}" STREQUAL "")
        set(_is_good FALSE)
        set(_hasp FALSE)
        if(DEFINED NCBI_PTB_THIS_SRC_ROOT)
            set(_src_root ${NCBI_PTB_THIS_SRC_ROOT})
        else()
            set(_src_root ${NCBI_SRC_ROOT})
        endif()
        foreach(_dir IN LISTS NCBI_PTBCFG_PROJECT_LIST)
            if("${_dir}" STREQUAL "")
                continue()
            endif()
            if(${_dir} STREQUAL "*")
                set(_is_good TRUE)
                continue()
            endif()
            NCBI_util_parse_sign( ${_dir} _value _negate)
            if(_negate)
                NCBI_util_match_path(${NCBI_CURRENT_SOURCE_DIR} ${_src_root}/${_value} _match)
                if(_match)
                    set(${_result} FALSE PARENT_SCOPE)
                    return()
                endif()
            else()
                set(_hasp TRUE)
                NCBI_util_match_path(${NCBI_CURRENT_SOURCE_DIR} ${_src_root}/${_value} _match)
                if(_match)
                    set(_is_good TRUE)
                endif()
            endif()
        endforeach()
        if (NOT _is_good AND _hasp)
            set(${_result} FALSE PARENT_SCOPE)
            return()
        endif()
    endif()

    if(NOT "${NCBI_PTBCFG_PROJECT_TARGETS}" STREQUAL "" AND NOT "${NCBI_PROJECT}" STREQUAL "")
        set(_is_good FALSE)
        set(_hasp FALSE)
        foreach(_prj IN LISTS NCBI_PTBCFG_PROJECT_TARGETS)
            if("${_prj}" STREQUAL "")
                continue()
            endif()
            if (${_prj} STREQUAL "*")
                set(_is_good TRUE)
                continue()
            endif()
            NCBI_util_parse_sign( ${_prj} _value _negate)
            if (_negate)
                if (${NCBI_PROJECT} MATCHES ${_value})
                    set(${_result} FALSE PARENT_SCOPE)
                    return()
                endif()
            else()
                set(_hasp TRUE)
                if (${NCBI_PROJECT} MATCHES ${_value})
                    set(_is_good TRUE)
                endif()
            endif()
        endforeach()
        if (NOT _is_good AND _hasp)
            set(${_result} FALSE PARENT_SCOPE)
            return()
        endif()
    endif()
    set(${_result} TRUE PARENT_SCOPE)
endfunction()

##############################################################################
function(NCBI_internal_print_project_info _prj)
    message("=============================================================================")
    get_property(_dir GLOBAL PROPERTY NCBI_PTBPROP_DIR_${_prj})
    message("PROJECT: ${_prj} (${_dir})")
    get_property(_x GLOBAL PROPERTY NCBI_PTBPROP_REQUIRES_${_prj})
    if(NOT "${_x}" STREQUAL "")
        list(SORT _x)
        message("  REQUIRES:  ${_x}")
    endif()
    get_property(_x GLOBAL PROPERTY NCBI_PTBPROP_COMPONENTS_${_prj})
    if(NOT "${_x}" STREQUAL "")
        list(SORT _x)
        message("  OPTIONAL COMPONENTS:  ${_x}")
    endif()
    get_property(_x GLOBAL PROPERTY NCBI_PTBPROP_DIRECT_DEPS_${_prj})
    if(NOT "${_x}" STREQUAL "")
        message("  DEPENDENCIES:  ${_x}")
        set(_needless "")
        foreach(_dep IN LISTS _x)
            get_property(_y GLOBAL PROPERTY NCBI_PTBPROP_DIRECT_DEPS_${_dep})
            if(NOT "${_y}" STREQUAL "")
                list(SORT _y)
                foreach(_subdep IN LISTS _y)
                    if(${_subdep} IN_LIST _x)
                        list(APPEND _needless ${_subdep})
                    endif()
                endforeach()
            endif()
        endforeach()
        if(NOT "${_needless}" STREQUAL "")
            list(REMOVE_DUPLICATES _needless)
            message("  NEEDLESS DEPENDENCIES:  ${_needless}")
        endif()
    endif()
    get_property(_x GLOBAL PROPERTY NCBI_PTBPROP_DEPS_${_prj})
    if(NOT "${_x}" STREQUAL "")
        list(SORT _x)
        message("-----------------------------------------------------------------------------")
        message("  ALL DEPENDENCIES:  ${_x}")
        foreach(_dep IN LISTS _x)
            get_property(_dir GLOBAL PROPERTY NCBI_PTBPROP_DIR_${_dep})
            message("  ${_dep} (${_dir})")
            get_property(_y GLOBAL PROPERTY NCBI_PTBPROP_REQUIRES_${_dep})
            if(NOT "${_y}" STREQUAL "")
                list(SORT _y)
                message("    REQUIRES:  ${_y}")
            endif()
            get_property(_y GLOBAL PROPERTY NCBI_PTBPROP_COMPONENTS_${_dep})
            if(NOT "${_y}" STREQUAL "")
                list(SORT _y)
                message("    OPTIONAL COMPONENTS:  ${_y}")
            endif()
            get_property(_y GLOBAL PROPERTY NCBI_PTBPROP_DIRECT_DEPS_${_dep})
            if(NOT "${_y}" STREQUAL "")
                list(SORT _y)
                message("    DEPENDENCIES:  ${_y}")
            endif()
        endforeach()
    endif()
    get_property(_x GLOBAL PROPERTY NCBI_PTBPROP_IMPLREQ_${_prj})
    if(NOT "${_x}" STREQUAL "")
        message("-----------------------------------------------------------------------------")
        message("  ALL REQUIRED COMPONENTS: ${_x}")
        foreach(_req IN LISTS _x)
            if (${_req})
                message("  ${_req}: ${${_req}}")
            elseif (NCBI_REQUIRE_${_req}_FOUND)
                message("  _${_req}: ${NCBI_REQUIRE_${_req}_FOUND}")
            elseif (NCBI_COMPONENT_${_req}_FOUND)
                message("  ${_req}")
                if (DEFINED NCBI_COMPONENT_${_req}_INCLUDE)
                    message("    INCLUDE: ${NCBI_COMPONENT_${_req}_INCLUDE}")
                endif()
                if (DEFINED NCBI_COMPONENT_${_req}_DEFINES)
                    message("    DEFINES: ${NCBI_COMPONENT_${_req}_DEFINES}")
                endif()
                if (DEFINED NCBI_COMPONENT_${_req}_LIBS)
                    message("    LIBS: ${NCBI_COMPONENT_${_req}_LIBS}")
                endif()
                if (DEFINED NCBI_COMPONENT_${_req}_BINPATH)
                    message("    BINPATH: ${NCBI_COMPONENT_${_req}_BINPATH}")
                endif()
            else()
                message("  ${_req} not defined")
            endif()
        endforeach()
    endif()
    message("=============================================================================")
endfunction()

##############################################################################
function(NCBI_internal_print_report _caption _counter)
    set(_report "")
    foreach( _type IN ITEMS CONSOLEAPP GUIAPP STATIC SHARED CUSTOM)
        get_property(_cnt GLOBAL PROPERTY NCBI_PTBPROP_${_counter}_${_type})
        if( NOT "${_cnt}" STREQUAL "" AND "${_cnt}" GREATER 0)
            if( NOT "${_report}" STREQUAL "")
                string(APPEND _report ",")
            endif()
            string(APPEND _report " ${_cnt} ")
            if(     ${_type} STREQUAL "CONSOLEAPP")
                string(APPEND _report "console app")
            elseif( ${_type} STREQUAL "GUIAPP")
                string(APPEND _report "GUI app")
            elseif( ${_type} STREQUAL "STATIC")
                string(APPEND _report "static lib")
            elseif( ${_type} STREQUAL "SHARED")
                string(APPEND _report "shared lib")
            elseif( ${_type} STREQUAL "CUSTOM")
                string(APPEND _report "custom target")
            endif()
            if( ${_cnt} GREATER 1)
                string(APPEND _report "s")
            endif()
        endif()
    endforeach()
    message("${_caption}: ${_report}")
endfunction()

##############################################################################
function(NCBI_internal_tweak_debugging_env)
    if (DEFINED NCBI_EXTERNAL_TREE_ROOT AND MSVC AND BUILD_SHARED_LIBS)
        if (${NCBI_${NCBI_PROJECT}_TYPE} STREQUAL "CONSOLEAPP" OR ${NCBI_${NCBI_PROJECT}_TYPE} STREQUAL "GUIAPP")
            set(_file "${CMAKE_CURRENT_BINARY_DIR}/${NCBI_PROJECT}.vcxproj.user")
            set(_bin "${NCBI_EXTERNAL_BUILD_ROOT}/${NCBI_DIRNAME_RUNTIME}")
            string(REPLACE "/" "\\" _bin ${_bin})
            if (NOT EXISTS "${_file}")
                set(_info)
                list(APPEND _info "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n")
                list(APPEND _info "<Project xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n")
                list(APPEND _info "  <PropertyGroup>\n")
                list(APPEND _info "    <LocalDebuggerEnvironment>PATH=${_bin}\\\$(Configuration)\;\$(VCRedistPaths)%PATH%\n")
                list(APPEND _info "</LocalDebuggerEnvironment>\n")
                list(APPEND _info "    <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>\n")
                list(APPEND _info "  </PropertyGroup>\n")
                list(APPEND _info "</Project>\n")
                file(WRITE ${_file} ${_info})
            endif()
        endif()
    endif()
endfunction()

##############################################################################
function(NCBI_internal_add_project)

    if (DEFINED NCBI_${NCBI_PROJECT}_PARTS AND NOT NCBI_PTBCFG_ALLOW_COMPOSITE)
        if (NOT NCBI_PTBMODE_COLLECT_DEPS)
            if (NCBI_VERBOSE_ALLPROJECTS OR NCBI_VERBOSE_PROJECT_${NCBI_PROJECT})
                message("${NCBI_PROJECT_ID} (${NCBI_CURRENT_SOURCE_DIR}) is excluded by configuration settings")
            endif()
        endif()
        if ("${ARGC}" GREATER "0")
            set(${ARGV0} FALSE PARENT_SCOPE)
        endif()
        return()
    endif()

    get_property(_hosted GLOBAL PROPERTY NCBI_PTBPROP_HOSTID_${NCBI_PROJECT_ID})
    if ("${_hosted}" STREQUAL "")
        get_property(_hosted GLOBAL PROPERTY NCBI_PTBPROP_HOST_${NCBI_PROJECT})
    endif()

    if (NCBI_PTBCFG_ENABLE_COLLECTOR AND NOT NCBI_PTBMODE_PARTS AND NOT NCBI_PTBMODE_COLLECT_DEPS)
        if(DEFINED NCBI_PTB_ALLOWED_PROJECTS)
            if(NOT ${NCBI_PROJECT} IN_LIST NCBI_PTB_ALLOWED_PROJECTS)
                if(NCBI_VERBOSE_ALLPROJECTS OR NCBI_VERBOSE_PROJECT_${NCBI_PROJECT})
                    message("${NCBI_PROJECT_ID} (${NCBI_CURRENT_SOURCE_DIR}) is excluded by user's request")
                endif()
                if ("${ARGC}" GREATER "0")
                    set(${ARGV0} FALSE PARENT_SCOPE)
                endif()
                return()
            endif()
        endif()

        if (NOT "${_hosted}" STREQUAL "")
            if(NCBI_VERBOSE_ALLPROJECTS OR NCBI_VERBOSE_PROJECT_${NCBI_PROJECT})
                message("${NCBI_PROJECT_ID} (${NCBI_CURRENT_SOURCE_DIR}) is excluded because it is part of ${_hosted}")
            endif()
            if ("${ARGC}" GREATER "0")
                set(${ARGV0} FALSE PARENT_SCOPE)
            endif()
            return()
        endif()
    endif()

    if(NOT NCBI_PTBCFG_ENABLE_COLLECTOR AND NOT NCBI_PTBMODE_PARTS)
        get_property(_count  GLOBAL PROPERTY NCBI_PTBPROP_TOTAL_${NCBI_${NCBI_PROJECT}_TYPE})
        math(EXPR _count "${_count} + 1")
        set_property(GLOBAL PROPERTY NCBI_PTBPROP_TOTAL_${NCBI_${NCBI_PROJECT}_TYPE} ${_count})
        NCBI_internal_process_project_filters(_allowed)
        if (NOT _allowed)
            if ("${ARGC}" GREATER "0")
                set(${ARGV0} FALSE PARENT_SCOPE)
            endif()
            return()
        endif()
    endif()

     if (NCBI_PTBMODE_COLLECT_DEPS)
        get_property(_prjdeps GLOBAL PROPERTY NCBI_PTBPROP_DIRECT_DEPS_${NCBI_PROJECT} SET)
        if (_prjdeps AND NOT DEFINED NCBI_${NCBI_PROJECT}_PARTS)
#            get_property(_dir GLOBAL PROPERTY NCBI_PTBPROP_DIR_${NCBI_PROJECT})
#            message("WARNING: Target ${NCBI_PROJECT_ID} (${NCBI_CURRENT_SOURCE_DIR}) is excluded")
#            message("         because there is already a target with the same name in ${_dir}")
            if ("${ARGC}" GREATER "0")
                set(${ARGV0} FALSE PARENT_SCOPE)
            endif()
            return()
        endif()
    endif()

if(NCBI_VERBOSE_ALLPROJECTS OR NCBI_VERBOSE_PROJECT_${NCBI_PROJECT})
message("-----------------------------------")
message("NCBI_PROJECT = ${NCBI_PROJECT}")
message("  TYPE = ${NCBI_${NCBI_PROJECT}_TYPE}")
message("  LOCATION = ${NCBI_CURRENT_SOURCE_DIR}")
message("  SOURCES = ${NCBI_${NCBI_PROJECT}_SOURCES} ${NCBI_${NCBI_PROJECT}_GENERATED_SOURCES}")
message("  RESOURCES = ${NCBI_${NCBI_PROJECT}_RESOURCES}")
message("  HEADERS = ${NCBI_${NCBI_PROJECT}_HEADERS}")
message("  REQUIRES = ${NCBI_${NCBI_PROJECT}_REQUIRES}")
message("  COMPONENTS = ${NCBI_${NCBI_PROJECT}_COMPONENTS}")
message("  NOPCH = ${NCBI_${NCBI_PROJECT}_NOPCH}")
message("  NCBILIB = ${NCBI_${NCBI_PROJECT}_NCBILIB}")
message("  EXTLIB = ${NCBI_${NCBI_PROJECT}_EXTLIB}")
message("  INCLUDES = ${NCBI_${NCBI_PROJECT}_INCLUDES}")
message("  DEFINES = ${NCBI_${NCBI_PROJECT}_DEFINES}")
message("  TAGS = ${NCBI_${NCBI_PROJECT}_PROJTAG}")
endif()

    if (DEFINED NCBI_${NCBI_PROJECT}_PARTS)
        NCBI_internal_process_parts(_result)
        if(NOT _result)
            if ("${ARGC}" GREATER "0")
                set(${ARGV0} FALSE PARENT_SCOPE)
            endif()
            return()
        endif()
    endif()

    set(NCBITMP_INCLUDES ${NCBITMP_PROJECT_INCLUDES} ${NCBI__INCLUDES} ${NCBI_${NCBI_PROJECT}_INCLUDES})
    set(NCBITMP_DEFINES  ${NCBITMP_PROJECT_DEFINES}  ${NCBI__DEFINES}  ${NCBI_${NCBI_PROJECT}_DEFINES})
    set(NCBITMP_NCBILIB  ${NCBITMP_PROJECT_NCBILIB}  ${NCBI__NCBILIB}  ${NCBI_${NCBI_PROJECT}_NCBILIB})
    set(NCBITMP_EXTLIB   ${NCBITMP_PROJECT_EXTLIB}   ${NCBI__EXTLIB}   ${NCBI_${NCBI_PROJECT}_EXTLIB})

    NCBI_internal_process_project_requires()
    if ( NOT "${NCBITMP_REQUIRE_NOTFOUND}" STREQUAL "" AND NOT NCBI_PTBMODE_COLLECT_DEPS)
        message("${NCBI_PROJECT} (${NCBI_CURRENT_SOURCE_DIR}) is excluded because of unmet requirements: ${NCBITMP_REQUIRE_NOTFOUND}")
        if (NOT NCBI_PTBMODE_PARTS)
            if ("${ARGC}" GREATER "0")
                set(${ARGV0} FALSE PARENT_SCOPE)
            endif()
            return()
        endif()
    endif()

    NCBI_internal_process_project_components()
    if ( NOT "${NCBITMP_COMPONENT_NOTFOUND}" STREQUAL "" AND NOT NCBI_PTBMODE_COLLECT_DEPS)
        message("${NCBI_PROJECT} (${NCBI_CURRENT_SOURCE_DIR}): cannot find optional component: ${NCBITMP_COMPONENT_NOTFOUND}")
    endif()
    if(NCBI_VERBOSE_ALLPROJECTS OR NCBI_VERBOSE_PROJECT_${NCBI_PROJECT})
        message("  NCBITMP_INCLUDES = ${NCBITMP_INCLUDES}")
        message("  NCBITMP_INCLUDES_SYSTEM = ${NCBITMP_INCLUDES_SYSTEM}")
        message("  NCBITMP_DEFINES = ${NCBITMP_DEFINES}")
        message("  NCBITMP_NCBILIB = ${NCBITMP_NCBILIB}")
        message("  NCBITMP_EXTLIB = ${NCBITMP_EXTLIB}")
    endif()
    NCBI_internal_verify_ncbilibs()
    NCBI_internal_verify_libs()
    if ( NOT "${NCBITMP_TARGET_NOTFOUND}" STREQUAL "" AND NOT NCBI_PTBMODE_COLLECT_DEPS)
        message("${NCBI_PROJECT} (${NCBI_CURRENT_SOURCE_DIR}) is excluded because it depends on missing targets: ${NCBITMP_TARGET_NOTFOUND}")
        if (NOT NCBI_PTBMODE_PARTS)
            if ("${ARGC}" GREATER "0")
                set(${ARGV0} FALSE PARENT_SCOPE)
            endif()
            return()
        endif()
    endif()

    if (NCBI_PTBMODE_COLLECT_DEPS)
        if (NCBI_PTBMODE_PARTS)
            set(NCBITMP_PROJECT_PART_IDS  ${NCBITMP_PROJECT_PART_IDS}  ${NCBI_PROJECT_ID}       PARENT_SCOPE )
            set(NCBITMP_PROJECT_PARTS     ${NCBITMP_PROJECT_PARTS}     ${NCBI_PROJECT_PARTNAME} PARENT_SCOPE )
        endif()
        set_property(GLOBAL PROPERTY NCBI_PTBPROP_DEPS_${NCBI_PROJECT} "${NCBITMP_NCBILIB}")
        set_property(GLOBAL PROPERTY NCBI_PTBPROP_DIRECT_DEPS_${NCBI_PROJECT} "${NCBITMP_NCBILIB}")
        set_property(GLOBAL PROPERTY NCBI_PTBPROP_DIR_${NCBI_PROJECT} "${NCBI_CURRENT_SOURCE_DIR}")
        if (DEFINED NCBI_${NCBI_PROJECT}_DATASPEC)
            set_property(GLOBAL PROPERTY NCBI_PTBPROP_DATASPEC_${NCBI_PROJECT} YES)
        endif()

        if(NOT NCBI_PTBMODE_PARTS)
            get_property(_allprojects GLOBAL PROPERTY NCBI_PTBPROP_ALL_PROJECTS)
            set(_allprojects ${_allprojects} ${NCBI_PROJECT})
            set_property(GLOBAL PROPERTY NCBI_PTBPROP_ALL_PROJECTS ${_allprojects})

            NCBI_internal_process_project_filters(_allowed)
            if (_allowed)
                get_property(_allowedprojects GLOBAL PROPERTY NCBI_PTBPROP_ALLOWED_PROJECTS)
                set(_allowedprojects ${_allowedprojects} ${NCBI_PROJECT})
                set_property(GLOBAL PROPERTY NCBI_PTBPROP_ALLOWED_PROJECTS ${_allowedprojects})
            endif()
            set(NCBI_PTB_CALLBACK_TARGET_PARSED ${NCBI_PROJECT})

            get_property(_count  GLOBAL PROPERTY NCBI_PTBPROP_TOTAL_${NCBI_${NCBI_PROJECT}_TYPE})
            math(EXPR _count "${_count} + 1")
            set_property(GLOBAL PROPERTY NCBI_PTBPROP_TOTAL_${NCBI_${NCBI_PROJECT}_TYPE} ${_count})

            if ("${ARGC}" GREATER "0")
                set(${ARGV0} FALSE PARENT_SCOPE)
            endif()
            return()
        endif()
    elseif(NOT NCBI_PTBCFG_ENABLE_COLLECTOR AND NCBI_PTBMODE_PARTS)
        set(NCBITMP_PROJECT_PART_IDS  ${NCBITMP_PROJECT_PART_IDS}  ${NCBI_PROJECT_ID}       PARENT_SCOPE )
        set(NCBITMP_PROJECT_PARTS     ${NCBITMP_PROJECT_PARTS}     ${NCBI_PROJECT_PARTNAME} PARENT_SCOPE )
    endif()

#message("processing ${NCBI_PROJECT_ID}")
    NCBI_internal_collect_sources() 
    NCBI_internal_collect_dataspec()
    NCBI_internal_collect_headers() 
    if (NCBI_PTBMODE_PARTS)
        set(NCBITMP_PROJECT_REQUIRES    ${NCBITMP_PROJECT_REQUIRES}   ${NCBI__REQUIRES}   ${NCBI_${NCBI_PROJECT}_REQUIRES}    PARENT_SCOPE)
        set(NCBITMP_PROJECT_COMPONENTS  ${NCBITMP_PROJECT_COMPONENTS} ${NCBI__COMPONENTS} ${NCBI_${NCBI_PROJECT}_COMPONENTS}  PARENT_SCOPE)
        set(NCBITMP_PROJECT_INCLUDES    ${NCBITMP_PROJECT_INCLUDES}   ${NCBI__INCLUDES}   ${NCBI_${NCBI_PROJECT}_INCLUDES}    PARENT_SCOPE)
        set(NCBITMP_PROJECT_DEFINES     ${NCBITMP_PROJECT_DEFINES}    ${NCBI__DEFINES}    ${NCBI_${NCBI_PROJECT}_DEFINES}     PARENT_SCOPE)
        set(NCBITMP_PROJECT_NCBILIB     ${NCBITMP_PROJECT_NCBILIB}    ${NCBI__NCBILIB}    ${NCBI_${NCBI_PROJECT}_NCBILIB}     PARENT_SCOPE)
        set(NCBITMP_PROJECT_EXTLIB      ${NCBITMP_PROJECT_EXTLIB}     ${NCBI__EXTLIB}     ${NCBI_${NCBI_PROJECT}_EXTLIB}      PARENT_SCOPE)
        set(NCBITMP_PROJECT_SOURCES     ${NCBITMP_PROJECT_SOURCES}    PARENT_SCOPE)
        set(NCBITMP_PROJECT_NOPCH       ${NCBITMP_PROJECT_NOPCH}      PARENT_SCOPE)
        set(NCBITMP_PROJECT_DATASPEC    ${NCBITMP_PROJECT_DATASPEC}   PARENT_SCOPE)
        set(NCBITMP_PROJECT_HEADERS     ${NCBITMP_PROJECT_HEADERS}    PARENT_SCOPE)
        if ("${ARGC}" GREATER "0")
            set(${ARGV0} FALSE PARENT_SCOPE)
        endif()
        return()
    endif()
    NCBI_internal_add_resources()
    NCBI_internal_add_dataspec()

#----------------------------------------------------------------------------
    if (${NCBI_${NCBI_PROJECT}_TYPE} STREQUAL "STATIC")

#message("add static library(${NCBI_PROJECT} STATIC ${NCBITMP_PROJECT_SOURCES} ${NCBITMP_PROJECT_HEADERS} ${NCBITMP_PROJECT_RESOURCES} ${NCBITMP_PROJECT_DATASPEC})")
#message("add static library ${NCBI_PROJECT}")
        add_library(${NCBI_PROJECT} STATIC ${NCBITMP_PROJECT_SOURCES} ${NCBITMP_PROJECT_HEADERS} ${NCBITMP_PROJECT_RESOURCES} ${NCBITMP_PROJECT_DATASPEC})
        set(_suffix ${CMAKE_STATIC_LIBRARY_SUFFIX})

#----------------------------------------------------------------------------
    elseif (${NCBI_${NCBI_PROJECT}_TYPE} STREQUAL "SHARED")

#message("add shared library(${NCBI_PROJECT} SHARED ${NCBITMP_PROJECT_SOURCES} ${NCBITMP_PROJECT_HEADERS} ${NCBITMP_PROJECT_RESOURCES} ${NCBITMP_PROJECT_DATASPEC})")
#message("add shared library ${NCBI_PROJECT}")
        add_library(${NCBI_PROJECT} SHARED ${NCBITMP_PROJECT_SOURCES} ${NCBITMP_PROJECT_HEADERS} ${NCBITMP_PROJECT_RESOURCES} ${NCBITMP_PROJECT_DATASPEC})
        set(_suffix ${CMAKE_SHARED_LIBRARY_SUFFIX})

#----------------------------------------------------------------------------
    elseif (${NCBI_${NCBI_PROJECT}_TYPE} STREQUAL "CONSOLEAPP")

#message("add_executable(${NCBI_PROJECT} ${NCBITMP_PROJECT_SOURCES} ${NCBITMP_PROJECT_HEADERS} ${NCBITMP_PROJECT_RESOURCES} ${NCBITMP_PROJECT_DATASPEC})")
#message("add executable ${NCBI_PROJECT}")
        add_executable(${NCBI_PROJECT} ${NCBITMP_PROJECT_SOURCES} ${NCBITMP_PROJECT_HEADERS} ${NCBITMP_PROJECT_RESOURCES} ${NCBITMP_PROJECT_DATASPEC})
        set(_suffix ${CMAKE_EXECUTABLE_SUFFIX})

#----------------------------------------------------------------------------
    elseif (${NCBI_${NCBI_PROJECT}_TYPE} STREQUAL "GUIAPP")

        add_executable(${NCBI_PROJECT} WIN32 ${NCBITMP_PROJECT_SOURCES} ${NCBITMP_PROJECT_HEADERS} ${NCBITMP_PROJECT_RESOURCES} ${NCBITMP_PROJECT_DATASPEC})
        set(_suffix ${CMAKE_EXECUTABLE_SUFFIX})

#----------------------------------------------------------------------------
    elseif (${NCBI_${NCBI_PROJECT}_TYPE} STREQUAL "CUSTOM")

        set(NCBI_${NCBI_PROJECT}_CALLBACK 0)
        variable_watch(NCBI_${NCBI_PROJECT}_CALLBACK ${NCBI_${NCBI_PROJECT}_DEFINITION})
        set(NCBI_${NCBI_PROJECT}_CALLBACK 1)

#----------------------------------------------------------------------------
    else()

        message("ERROR: ${NCBI_PROJECT} (${NCBI_CURRENT_SOURCE_DIR}) unsupported project type ${NCBI_${NCBI_PROJECT}_TYPE}")
        if ("${ARGC}" GREATER "0")
            set(${ARGV0} FALSE PARENT_SCOPE)
        endif()
        return()

    endif()

	if (DEFINED NCBI_DEFAULT_CFGPROPS)
		if(MSVC)
			set_target_properties(${NCBI_PROJECT} PROPERTIES VS_USER_PROPS "${NCBI_DEFAULT_CFGPROPS}")
		endif()
	endif()
    if (DEFINED NCBI_${NCBI_PROJECT}_OUTPUT)
        if(NOT DEFINED NCBI_EXTERNAL_TREE_ROOT AND NOT ${NCBI_PROJECT} STREQUAL ${NCBI_${NCBI_PROJECT}_OUTPUT})
            get_property(_dir GLOBAL PROPERTY NCBI_PTBPROP_DIR_${NCBI_${NCBI_PROJECT}_OUTPUT})
            if (NOT ${_dir} STREQUAL "" AND (NOT ${_dir} STREQUAL ${NCBI_CURRENT_SOURCE_DIR} OR TARGET ${NCBI_${NCBI_PROJECT}_OUTPUT}))
                message("WARNING: App target ${NCBI_${NCBI_PROJECT}_OUTPUT} (${NCBI_CURRENT_SOURCE_DIR}) cannot be created")
                message("         because there is already a target with the same name in ${_dir}")
                message("         App target ${NCBI_${NCBI_PROJECT}_OUTPUT} will be renamed into ${NCBI_PROJECT}")
            elseif(NOT NCBI_PTBCFG_ENABLE_COLLECTOR)
                message("WARNING: App target ${NCBI_${NCBI_PROJECT}_OUTPUT} (${NCBI_CURRENT_SOURCE_DIR}) cannot be created")
                message("         because there is already a target with the same name elsewhere")
                message("         App target ${NCBI_${NCBI_PROJECT}_OUTPUT} will be renamed into ${NCBI_PROJECT}")
            endif()
        endif()
        set_target_properties(${NCBI_PROJECT} PROPERTIES OUTPUT_NAME ${NCBI_${NCBI_PROJECT}_OUTPUT})
    endif()

    get_property(_count  GLOBAL PROPERTY NCBI_PTBPROP_COUNT_${NCBI_${NCBI_PROJECT}_TYPE})
    math(EXPR _count "${_count} + 1")
    set_property(GLOBAL PROPERTY NCBI_PTBPROP_COUNT_${NCBI_${NCBI_PROJECT}_TYPE} ${_count})

if(NCBI_VERBOSE_ALLPROJECTS OR NCBI_VERBOSE_PROJECT_${NCBI_PROJECT})
message("  ADDED: ${NCBI_CURRENT_SOURCE_DIR}/${NCBI_PROJECT_ID}")
message("  NCBITMP_PROJECT_SOURCES ${NCBITMP_PROJECT_SOURCES}")
message("  NCBITMP_PROJECT_HEADERS ${NCBITMP_PROJECT_HEADERS}")
message("  NCBITMP_PROJECT_RESOURCES ${NCBITMP_PROJECT_RESOURCES}")
#message("  NCBI_SRC_ROOT ${NCBI_SRC_ROOT}")
#message("  NCBI_INC_ROOT ${NCBI_INC_ROOT}")
endif()

    if (${NCBI_${NCBI_PROJECT}_TYPE} STREQUAL "CUSTOM")

        get_property(_prjdeps GLOBAL PROPERTY NCBI_PTBPROP_DIRECT_DEPS_${NCBI_PROJECT})
        if (NOT "${_prjdeps}" STREQUAL "")
            add_dependencies(${NCBI_PROJECT} ${_prjdeps})
        endif()

    else()
        target_include_directories(${NCBI_PROJECT} SYSTEM PRIVATE ${NCBITMP_INCLUDES_SYSTEM})
        target_include_directories(${NCBI_PROJECT} PRIVATE ${NCBITMP_INCLUDES})
        target_compile_definitions(${NCBI_PROJECT} PRIVATE ${NCBITMP_DEFINES})

if(OFF)
# this does not seem to have any effect
        if (XCODE AND NOT BUILD_SHARED_LIBS)
            set_target_properties(${NCBI_PROJECT} PROPERTIES XCODE_ATTRIBUTE_STANDARD_C_PLUS_PLUS_LIBRARY_TYPE "static")
            set_target_properties(${NCBI_PROJECT} PROPERTIES XCODE_ATTRIBUTE_GCC_SYMBOLS_PRIVATE_EXTERN "YES")
        endif()
endif()

#message("target_link_libraries: ${NCBI_PROJECT}     ${NCBITMP_NCBILIB} ${NCBITMP_EXTLIB}")
        set(_libs ${NCBITMP_NCBILIB} ${NCBITMP_EXTLIB})
        if ("${_libs}" STREQUAL "")
            set(_libs ${ORIG_LIBS})
        endif()
        target_link_libraries(     ${NCBI_PROJECT}         ${_libs})

        if (DEFINED _suffix)
            set_target_properties( ${NCBI_PROJECT} PROPERTIES PROJECT_LABEL ${NCBI_PROJECT}${_suffix})
        endif()
        NCBI_internal_define_precompiled_header_usage()
    endif()
    NCBI_internal_tweak_debugging_env()

    set(NCBI_PTB_CALLBACK_TARGET_ADDED ${NCBI_PROJECT})

if(NCBI_VERBOSE_ALLPROJECTS OR NCBI_VERBOSE_PROJECT_${NCBI_PROJECT})
message("-----------------------------------")
endif()

    if ("${ARGC}" GREATER "0")
        set(${ARGV0} TRUE PARENT_SCOPE)
    endif()
endfunction()

##############################################################################
##############################################################################

macro(NCBI_util_load_file _file _result)
    get_filename_component(_path ${_file} DIRECTORY)
    if (EXISTS "${_file}" AND NOT IS_DIRECTORY "${_file}")
        file(STRINGS "${_file}" _list)
        foreach( _item IN LISTS _list)
            if ("${_item}" STREQUAL "")
                continue()
            endif()
            if ("${_item}" MATCHES "#")
                if ("${_item}" MATCHES "#include")
                    string(REPLACE "#include" "" _item ${_item})
                    string(REPLACE " " "" _item ${_item})
                    string(REPLACE "\"" "" _item ${_item})
                    NCBI_util_load_file(${_path}/${_item} ${_result})
                endif()
                continue()
            endif()
            string(REPLACE " " ";" _tmp ${_item})
            list(GET _tmp 0 _item)
            list(APPEND ${_result} ${_item})
        endforeach()
    else()
        message("WARNING: unable to load ${_file}")
    endif()
endmacro()


if("${NCBI_PTBCFG_PROJECT_LIST}" STREQUAL "")
    unset(NCBI_PTBCFG_PROJECT_LIST)
endif()
if("${NCBI_PTBCFG_PROJECT_TAGS}" STREQUAL "")
    unset(NCBI_PTBCFG_PROJECT_TAGS)
endif()
if("${NCBI_PTBCFG_PROJECT_TARGETS}" STREQUAL "")
    unset(NCBI_PTBCFG_PROJECT_TARGETS)
endif()

if(DEFINED NCBI_PTBCFG_PROJECT_LIST AND EXISTS "${NCBI_PTBCFG_PROJECT_LIST}")
    if (NOT IS_DIRECTORY "${NCBI_PTBCFG_PROJECT_LIST}")
        string(REPLACE "\\" "/" NCBI_PTBCFG_PROJECT_LIST ${NCBI_PTBCFG_PROJECT_LIST})
        NCBI_util_load_file("${NCBI_PTBCFG_PROJECT_LIST}" NCBI_PTBCFG_PROJECT_LIST)
        list(REMOVE_AT NCBI_PTBCFG_PROJECT_LIST 0) 
        list(REMOVE_DUPLICATES NCBI_PTBCFG_PROJECT_LIST) 
    endif()
endif()
set(_lst ${NCBI_PTBCFG_PROJECT_LIST})
set(NCBI_PTBCFG_PROJECT_LIST "")
foreach(_item IN LISTS _lst)
    string(REPLACE "\\" "/" _item ${_item})
    list(APPEND NCBI_PTBCFG_PROJECT_LIST ${_item})
endforeach()

if(DEFINED NCBI_PTBCFG_PROJECT_TAGS AND EXISTS "${NCBI_PTBCFG_PROJECT_TAGS}")
    if (NOT IS_DIRECTORY "${NCBI_PTBCFG_PROJECT_TAGS}")
        file(STRINGS "${NCBI_PTBCFG_PROJECT_TAGS}" NCBI_PTBCFG_PROJECT_TAGS)
    endif()
endif()

if(DEFINED NCBI_PTBCFG_PROJECT_TARGETS AND EXISTS "${NCBI_PTBCFG_PROJECT_TARGETS}")
    if (NOT IS_DIRECTORY "${NCBI_PTBCFG_PROJECT_TARGETS}")
        file(STRINGS "${NCBI_PTBCFG_PROJECT_TARGETS}" NCBI_PTBCFG_PROJECT_TARGETS)
    endif()
endif()

if(DEFINED NCBI_VERBOSE_PROJECTS)
    foreach(_prj IN LISTS NCBI_VERBOSE_PROJECTS)
        if ("${_prj}" STREQUAL "*")
            set(NCBI_VERBOSE_ALLPROJECTS   ON)
        else()
            set(NCBI_VERBOSE_PROJECT_${_prj}   ON)
        endif()
    endforeach()
endif()
