| # Distributed under the OSI-approved BSD 3-Clause License.  See accompanying | 
 | # file LICENSE.rst or https://cmake.org/licensing for details. | 
 |  | 
 | #[=======================================================================[.rst: | 
 | CSharpUtilities | 
 | --------------- | 
 |  | 
 | .. versionadded:: 3.8 | 
 |  | 
 | This utility module is intended to simplify the configuration of CSharp/.NET | 
 | targets and provides a collection of commands for managing CSharp targets | 
 | with :ref:`Visual Studio Generators`, version 2010 and newer. | 
 |  | 
 | Load this module in a CMake project with: | 
 |  | 
 | .. code-block:: cmake | 
 |  | 
 |   include(CSharpUtilities) | 
 |  | 
 | Commands | 
 | ^^^^^^^^ | 
 |  | 
 | This module provides the following commands: | 
 |  | 
 | .. rubric:: Main Commands | 
 |  | 
 | - :command:`csharp_set_windows_forms_properties` | 
 | - :command:`csharp_set_designer_cs_properties` | 
 | - :command:`csharp_set_xaml_cs_properties` | 
 |  | 
 | .. rubric:: Helper Commands | 
 |  | 
 | - :command:`csharp_get_filename_keys` | 
 | - :command:`csharp_get_filename_key_base` | 
 | - :command:`csharp_get_dependentupon_name` | 
 |  | 
 | Main Commands | 
 | """"""""""""" | 
 |  | 
 | .. command:: csharp_set_windows_forms_properties | 
 |  | 
 |   Sets source file properties for use of Windows Forms: | 
 |  | 
 |   .. code-block:: cmake | 
 |  | 
 |     csharp_set_windows_forms_properties([<files>...]) | 
 |  | 
 |   ``<files>...`` | 
 |     A list of zero or more source files which are relevant for setting the | 
 |     :prop_sf:`VS_CSHARP_<tagname>` source file properties. This typically | 
 |     includes files with ``.cs``, ``.resx``, and ``.Designer.cs`` extensions. | 
 |  | 
 |   Use this command when a CSharp target in the project uses Windows Forms. | 
 |  | 
 |   This command searches in the provided list of files for pairs of related | 
 |   files ending with ``.Designer.cs`` (*designer* files) or ``.resx`` | 
 |   (*resource* files).  For each such file, a corresponding base ``.cs`` | 
 |   file is searched (with the same base name).  When found, the | 
 |   :prop_sf:`VS_CSHARP_<tagname>` source file properties are set as follows: | 
 |  | 
 |   For the **.cs** file: | 
 |    - ``VS_CSHARP_SubType "Form"`` | 
 |  | 
 |   For the **.Designer.cs** file (if it exists): | 
 |    - ``VS_CSHARP_DependentUpon <cs-filename>`` | 
 |    - ``VS_CSHARP_DesignTime ""`` (tag is removed if previously defined) | 
 |    - ``VS_CSHARP_AutoGen ""`` (tag is removed if previously defined) | 
 |  | 
 |   For the **.resx** file (if it exists): | 
 |    - ``VS_RESOURCE_GENERATOR ""`` (tag is removed if previously defined) | 
 |    - ``VS_CSHARP_DependentUpon <cs-filename>`` | 
 |    - ``VS_CSHARP_SubType "Designer"`` | 
 |  | 
 | .. command:: csharp_set_designer_cs_properties | 
 |  | 
 |   Sets source file properties for ``.Designer.cs`` files depending on | 
 |   sibling filenames: | 
 |  | 
 |   .. code-block:: cmake | 
 |  | 
 |     csharp_set_designer_cs_properties([<files>...]) | 
 |  | 
 |   ``<files>...`` | 
 |     A list of zero or more source files which are relevant for setting the | 
 |     :prop_sf:`VS_CSHARP_<tagname>` source file properties.  This typically | 
 |     includes files with ``.resx``, ``.settings``, and ``.Designer.cs`` | 
 |     extensions. | 
 |  | 
 |   Use this command, if the CSharp target does **not** use Windows Forms | 
 |   (for Windows Forms use :command:`csharp_set_windows_forms_properties` | 
 |   instead). | 
 |  | 
 |   This command searches through the provided list for files ending in | 
 |   ``.Designer.cs`` (*designer* files).  For each such file, it looks for | 
 |   sibling files with the same base name but different extensions.  If a | 
 |   matching file is found, the appropriate source file properties are set on | 
 |   the corresponding ``.Designer.cs`` file based on the matched extension: | 
 |  | 
 |   If match is **.resx** file: | 
 |  | 
 |   - ``VS_CSHARP_AutoGen "True"`` | 
 |   - ``VS_CSHARP_DesignTime "True"`` | 
 |   - ``VS_CSHARP_DependentUpon <resx-filename>`` | 
 |  | 
 |   If match is **.cs** file: | 
 |  | 
 |   - ``VS_CSHARP_DependentUpon <cs-filename>`` | 
 |  | 
 |   If match is **.settings** file: | 
 |  | 
 |   - ``VS_CSHARP_AutoGen "True"`` | 
 |   - ``VS_CSHARP_DesignTimeSharedInput "True"`` | 
 |   - ``VS_CSHARP_DependentUpon <settings-filename>`` | 
 |  | 
 | .. note:: | 
 |  | 
 |     Because the source file properties of the ``.Designer.cs`` file are set | 
 |     according to the found matches and every match sets the | 
 |     :prop_sf:`VS_CSHARP_DependentUpon <VS_CSHARP_<tagname>>` | 
 |     source file property, there should only be one match for | 
 |     each ``Designer.cs`` file. | 
 |  | 
 | .. command:: csharp_set_xaml_cs_properties | 
 |  | 
 |   Sets source file properties for use of Windows Presentation Foundation (WPF) | 
 |   and XAML: | 
 |  | 
 |   .. code-block:: cmake | 
 |  | 
 |     csharp_set_xaml_cs_properties([<files>...]) | 
 |  | 
 |   Use this command, if the CSharp target uses WPF/XAML. | 
 |  | 
 |   ``<files>...`` | 
 |     A list of zero or more source files which are relevant for setting the | 
 |     :prop_sf:`VS_CSHARP_<tagname>` source file properties.  This typically | 
 |     includes files with ``.cs``, ``.xaml``, and ``.xaml.cs`` extensions. | 
 |  | 
 |   This command searches the provided file list for files ending with | 
 |   ``.xaml.cs``.  For each such XAML code-behind file, a corresponding | 
 |   ``.xaml`` file with the same base name is searched.  If found, the | 
 |   following source file property is set on the ``.xaml.cs`` file: | 
 |  | 
 |   - ``VS_CSHARP_DependentUpon <xaml-filename>`` | 
 |  | 
 | Helper Commands | 
 | """"""""""""""" | 
 |  | 
 | These commands are used by the above main commands and typically aren't | 
 | used directly: | 
 |  | 
 | .. command:: csharp_get_filename_keys | 
 |  | 
 |   Computes a normalized list of key values to identify source files | 
 |   independently of relative or absolute paths given in CMake and eliminates | 
 |   case sensitivity: | 
 |  | 
 |   .. code-block:: cmake | 
 |  | 
 |     csharp_get_filename_keys(<variable> [<files>...]) | 
 |  | 
 |   ``<variable>`` | 
 |     Name of the variable in which the list of computed keys is stored. | 
 |  | 
 |   ``<files>...`` | 
 |     Zero or more source file paths as given to CSharp target using commands | 
 |     like :command:`add_library`, or :command:`add_executable`. | 
 |  | 
 |   This command canonicalizes file paths to ensure consistent identification | 
 |   of source files.  This is useful when source files are added to a target | 
 |   using different path forms.  Without normalization, CMake may treat paths | 
 |   like ``myfile.Designer.cs`` and | 
 |   ``${CMAKE_CURRENT_SOURCE_DIR}/myfile.Designer.cs`` as different files, | 
 |   which can cause issues when setting source file properties. | 
 |  | 
 |   For example, the following code will fail to set properties because the | 
 |   file paths do not match exactly: | 
 |  | 
 |   .. code-block:: cmake | 
 |  | 
 |     add_library(lib myfile.cs ${CMAKE_CURRENT_SOURCE_DIR}/myfile.Designer.cs) | 
 |  | 
 |     set_source_files_properties( | 
 |       myfile.Designer.cs | 
 |       PROPERTIES VS_CSHARP_DependentUpon myfile.cs | 
 |     ) | 
 |  | 
 | .. command:: csharp_get_filename_key_base | 
 |  | 
 |   Returns the full filepath and name **without** extension of a key: | 
 |  | 
 |   .. code-block:: cmake | 
 |  | 
 |     csharp_get_filename_key_base(<base> <key>) | 
 |  | 
 |   ``<base>`` | 
 |     Name of the variable with the computed base value of the ``<key>`` | 
 |     without the file extension. | 
 |  | 
 |   ``<key>`` | 
 |     The key of which the base will be computed.  Expected to be a | 
 |     uppercase full filename from :command:`csharp_get_filename_keys`. | 
 |  | 
 | .. command:: csharp_get_dependentupon_name | 
 |  | 
 |   Computes a string which can be used as value for the source file property | 
 |   :prop_sf:`VS_CSHARP_<tagname>` with ``<tagname>`` being ``DependentUpon``: | 
 |  | 
 |   .. code-block:: cmake | 
 |  | 
 |     csharp_get_dependentupon_name(<variable> <file>) | 
 |  | 
 |   ``<variable>`` | 
 |     Name of the variable with the result value.  Value contains the name | 
 |     of the ``<file>`` without directory. | 
 |  | 
 |   ``<file>`` | 
 |     Filename to convert for using in the value of the | 
 |     ``VS_CSHARP_DependentUpon`` source file property. | 
 | #]=======================================================================] | 
 |  | 
 | function(csharp_get_filename_keys OUT) | 
 |   set(${OUT} "") | 
 |   foreach(f ${ARGN}) | 
 |     get_filename_component(f ${f} REALPATH) | 
 |     string(TOUPPER ${f} f) | 
 |     list(APPEND ${OUT} ${f}) | 
 |   endforeach() | 
 |   set(${OUT} "${${OUT}}" PARENT_SCOPE) | 
 | endfunction() | 
 |  | 
 | function(csharp_get_filename_key_base base key) | 
 |   get_filename_component(dir ${key} DIRECTORY) | 
 |   get_filename_component(fil ${key} NAME_WE) | 
 |   set(${base} "${dir}/${fil}" PARENT_SCOPE) | 
 | endfunction() | 
 |  | 
 | function(csharp_get_dependentupon_name out in) | 
 |   get_filename_component(${out} ${in} NAME) | 
 |   set(${out} ${${out}} PARENT_SCOPE) | 
 | endfunction() | 
 |  | 
 | function(csharp_set_windows_forms_properties) | 
 |   csharp_get_filename_keys(fileKeys ${ARGN}) | 
 |   foreach(key ${fileKeys}) | 
 |     get_filename_component(ext ${key} EXT) | 
 |     if(${ext} STREQUAL ".DESIGNER.CS" OR | 
 |        ${ext} STREQUAL ".RESX") | 
 |       csharp_get_filename_key_base(NAME_BASE ${key}) | 
 |       list(FIND fileKeys "${NAME_BASE}.CS" FILE_INDEX) | 
 |       if(NOT ${FILE_INDEX} EQUAL -1) | 
 |         list(GET ARGN ${FILE_INDEX} FILE_NAME) | 
 |         # set properties of main form file | 
 |         set_source_files_properties("${FILE_NAME}" | 
 |           PROPERTIES | 
 |           VS_CSHARP_SubType "Form") | 
 |         csharp_get_dependentupon_name(LINK "${FILE_NAME}") | 
 |         # set properties of designer file (if found) | 
 |         list(FIND fileKeys "${NAME_BASE}.DESIGNER.CS" FILE_INDEX) | 
 |         if(NOT ${FILE_INDEX} EQUAL -1) | 
 |           list(GET ARGN ${FILE_INDEX} FILE_NAME) | 
 |           set_source_files_properties("${FILE_NAME}" | 
 |             PROPERTIES | 
 |             VS_CSHARP_DependentUpon "${LINK}" | 
 |             VS_CSHARP_DesignTime "" | 
 |             VS_CSHARP_AutoGen "") | 
 |         endif() | 
 |         # set properties of corresponding resource file (if found) | 
 |         list(FIND fileKeys "${NAME_BASE}.RESX" FILE_INDEX) | 
 |         if(NOT ${FILE_INDEX} EQUAL -1) | 
 |           list(GET ARGN ${FILE_INDEX} FILE_NAME) | 
 |           set_source_files_properties("${FILE_NAME}" | 
 |             PROPERTIES | 
 |             VS_RESOURCE_GENERATOR "" | 
 |             VS_CSHARP_DependentUpon "${LINK}" | 
 |             VS_CSHARP_SubType "Designer") | 
 |         endif() | 
 |       endif() | 
 |     endif() | 
 |   endforeach() | 
 | endfunction() | 
 |  | 
 | function(csharp_set_designer_cs_properties) | 
 |   csharp_get_filename_keys(fileKeys ${ARGN}) | 
 |   set(INDEX -1) | 
 |   foreach(key ${fileKeys}) | 
 |     math(EXPR INDEX "${INDEX}+1") | 
 |     list(GET ARGN ${INDEX} source) | 
 |     get_filename_component(ext ${key} EXT) | 
 |     if(${ext} STREQUAL ".DESIGNER.CS") | 
 |       csharp_get_filename_key_base(NAME_BASE ${key}) | 
 |       if("${NAME_BASE}.RESX" IN_LIST fileKeys) | 
 |         list(FIND fileKeys "${NAME_BASE}.RESX" FILE_INDEX) | 
 |         list(GET ARGN ${FILE_INDEX} FILE_NAME) | 
 |         csharp_get_dependentupon_name(LINK "${FILE_NAME}") | 
 |         set_source_files_properties("${source}" | 
 |           PROPERTIES | 
 |           VS_CSHARP_AutoGen "True" | 
 |           VS_CSHARP_DesignTime "True" | 
 |           VS_CSHARP_DependentUpon "${LINK}") | 
 |       elseif("${NAME_BASE}.CS" IN_LIST fileKeys) | 
 |         list(FIND fileKeys "${NAME_BASE}.CS" FILE_INDEX) | 
 |         list(GET ARGN ${FILE_INDEX} FILE_NAME) | 
 |         csharp_get_dependentupon_name(LINK "${FILE_NAME}") | 
 |         set_source_files_properties("${source}" | 
 |           PROPERTIES | 
 |           VS_CSHARP_DependentUpon "${LINK}") | 
 |       elseif("${NAME_BASE}.SETTINGS" IN_LIST fileKeys) | 
 |         list(FIND fileKeys "${NAME_BASE}.SETTINGS" FILE_INDEX) | 
 |         list(GET ARGN ${FILE_INDEX} FILE_NAME) | 
 |         csharp_get_dependentupon_name(LINK "${FILE_NAME}") | 
 |         set_source_files_properties("${source}" | 
 |           PROPERTIES | 
 |           VS_CSHARP_AutoGen "True" | 
 |           VS_CSHARP_DesignTimeSharedInput "True" | 
 |           VS_CSHARP_DependentUpon "${LINK}") | 
 |       endif() | 
 |     endif() | 
 |   endforeach() | 
 | endfunction() | 
 |  | 
 | function(csharp_set_xaml_cs_properties) | 
 |   csharp_get_filename_keys(fileKeys ${ARGN}) | 
 |   set(INDEX -1) | 
 |   foreach(key ${fileKeys}) | 
 |     math(EXPR INDEX "${INDEX}+1") | 
 |     list(GET ARGN ${INDEX} source) | 
 |     get_filename_component(ext ${key} EXT) | 
 |     if(${ext} STREQUAL ".XAML.CS") | 
 |       csharp_get_filename_key_base(NAME_BASE ${key}) | 
 |       if("${NAME_BASE}.XAML" IN_LIST fileKeys) | 
 |         list(FIND fileKeys "${NAME_BASE}.XAML" FILE_INDEX) | 
 |         list(GET ARGN ${FILE_INDEX} FILE_NAME) | 
 |         csharp_get_dependentupon_name(LINK "${FILE_NAME}") | 
 |         set_source_files_properties("${source}" | 
 |           PROPERTIES | 
 |           VS_CSHARP_DependentUpon "${LINK}") | 
 |       endif() | 
 |     endif() | 
 |   endforeach() | 
 | endfunction() |