1# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2# file Copyright.txt or https://cmake.org/licensing for details.
3
4#[=======================================================================[.rst:
5CSharpUtilities
6---------------
7
8.. versionadded:: 3.8
9
10Functions to make configuration of CSharp/.NET targets easier.
11
12A collection of CMake utility functions useful for dealing with CSharp
13targets for Visual Studio generators from version 2010 and later.
14
15The following functions are provided by this module:
16
17**Main functions**
18
19- :command:`csharp_set_windows_forms_properties`
20- :command:`csharp_set_designer_cs_properties`
21- :command:`csharp_set_xaml_cs_properties`
22
23**Helper functions**
24
25- :command:`csharp_get_filename_keys`
26- :command:`csharp_get_filename_key_base`
27- :command:`csharp_get_dependentupon_name`
28
29Main functions provided by the module
30^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
31
32.. command:: csharp_set_windows_forms_properties
33
34  Sets source file properties for use of Windows Forms. Use this, if your CSharp
35  target uses Windows Forms::
36
37    csharp_set_windows_forms_properties([<file1> [<file2> [...]]])
38
39  ``<fileN>``
40    List of all source files which are relevant for setting the
41    :prop_sf:`VS_CSHARP_<tagname>` properties (including ``.cs``, ``.resx`` and
42    ``.Designer.cs`` extensions).
43
44  In the list of all given files for all files ending with ``.Designer.cs`` and
45  ``.resx`` is searched.  For every *designer* or *resource* file a file with the
46  same base name but only ``.cs`` as extension is searched.  If this is found, the
47  :prop_sf:`VS_CSHARP_<tagname>` properties are set as follows:
48
49  for the **.cs** file:
50   - VS_CSHARP_SubType "Form"
51
52  for the **.Designer.cs** file (if it exists):
53   - VS_CSHARP_DependentUpon <cs-filename>
54   - VS_CSHARP_DesignTime "" (delete tag if previously defined)
55   - VS_CSHARP_AutoGen ""(delete tag if previously defined)
56
57  for the **.resx** file (if it exists):
58   - VS_RESOURCE_GENERATOR "" (delete tag if previously defined)
59   - VS_CSHARP_DependentUpon <cs-filename>
60   - VS_CSHARP_SubType "Designer"
61
62.. command:: csharp_set_designer_cs_properties
63
64  Sets source file properties of ``.Designer.cs`` files depending on
65  sibling filenames. Use this, if your CSharp target does **not**
66  use Windows Forms (for Windows Forms use
67  :command:`csharp_set_designer_cs_properties` instead)::
68
69    csharp_set_designer_cs_properties([<file1> [<file2> [...]]])
70
71  ``<fileN>``
72    List of all source files which are relevant for setting the
73    :prop_sf:`VS_CSHARP_<tagname>` properties (including ``.cs``,
74    ``.resx``, ``.settings`` and ``.Designer.cs`` extensions).
75
76  In the list of all given files for all files ending with
77  ``.Designer.cs`` is searched. For every *designer* file all files
78  with the same base name but different extensions are searched. If
79  a match is found, the source file properties of the *designer* file
80  are set depending on the extension of the matched file:
81
82  if match is **.resx** file:
83   - VS_CSHARP_AutoGen "True"
84   - VS_CSHARP_DesignTime "True"
85   - VS_CSHARP_DependentUpon <resx-filename>
86
87  if match is **.cs** file:
88   - VS_CSHARP_DependentUpon <cs-filename>
89
90  if match is **.settings** file:
91   - VS_CSHARP_AutoGen "True"
92   - VS_CSHARP_DesignTimeSharedInput "True"
93   - VS_CSHARP_DependentUpon <settings-filename>
94
95.. note::
96
97    Because the source file properties of the ``.Designer.cs`` file are set according
98    to the found matches and every match sets the **VS_CSHARP_DependentUpon**
99    property, there should only be one match for each ``Designer.cs`` file.
100
101.. command:: csharp_set_xaml_cs_properties
102
103  Sets source file properties for use of Windows Presentation Foundation (WPF) and
104  XAML. Use this, if your CSharp target uses WPF/XAML::
105
106    csharp_set_xaml_cs_properties([<file1> [<file2> [...]]])
107
108  ``<fileN>``
109    List of all source files which are relevant for setting the
110    :prop_sf:`VS_CSHARP_<tagname>` properties (including ``.cs``,
111    ``.xaml``, and ``.xaml.cs`` extensions).
112
113  In the list of all given files for all files ending with
114  ``.xaml.cs`` is searched. For every *xaml-cs* file, a file
115  with the same base name but extension ``.xaml`` is searched.
116  If a match is found, the source file properties of the ``.xaml.cs``
117  file are set:
118
119   - VS_CSHARP_DependentUpon <xaml-filename>
120
121Helper functions which are used by the above ones
122^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
123
124.. command:: csharp_get_filename_keys
125
126  Helper function which computes a list of key values to identify
127  source files independently of relative/absolute paths given in cmake
128  and eliminates case sensitivity::
129
130    csharp_get_filename_keys(OUT [<file1> [<file2> [...]]])
131
132  ``OUT``
133    Name of the variable in which the list of keys is stored
134
135  ``<fileN>``
136    filename(s) as given to to CSharp target using :command:`add_library`
137    or :command:`add_executable`
138
139  In some way the function applies a canonicalization to the source names.
140  This is necessary to find file matches if the files have been added to
141  the target with different directory prefixes:
142
143  .. code-block:: cmake
144
145    add_library(lib
146      myfile.cs
147      ${CMAKE_CURRENT_SOURCE_DIR}/myfile.Designer.cs)
148
149    set_source_files_properties(myfile.Designer.cs PROPERTIES
150      VS_CSHARP_DependentUpon myfile.cs)
151
152    # this will fail, because in cmake
153    #  - ${CMAKE_CURRENT_SOURCE_DIR}/myfile.Designer.cs
154    #  - myfile.Designer.cs
155    # are not the same source file. The source file property is not set.
156
157.. command:: csharp_get_filename_key_base
158
159  Returns the full filepath and name **without** extension of a key.
160  KEY is expected to be a key from csharp_get_filename_keys. In BASE
161  the value of KEY without the file extension is returned::
162
163    csharp_get_filename_key_base(BASE KEY)
164
165  ``BASE``
166    Name of the variable with the computed "base" of ``KEY``.
167
168  ``KEY``
169    The key of which the base will be computed. Expected to be a
170    upper case full filename.
171
172.. command:: csharp_get_dependentupon_name
173
174  Computes a string which can be used as value for the source file property
175  :prop_sf:`VS_CSHARP_<tagname>` with *target* being ``DependentUpon``::
176
177    csharp_get_dependentupon_name(NAME FILE)
178
179  ``NAME``
180    Name of the variable with the result value
181
182  ``FILE``
183    Filename to convert to ``<DependentUpon>`` value
184
185  Actually this is only the filename without any path given at the moment.
186
187#]=======================================================================]
188
189cmake_policy(PUSH)
190cmake_policy(SET CMP0057 NEW) # if IN_LIST
191
192function(csharp_get_filename_keys OUT)
193  set(${OUT} "")
194  foreach(f ${ARGN})
195    get_filename_component(f ${f} REALPATH)
196    string(TOUPPER ${f} f)
197    list(APPEND ${OUT} ${f})
198  endforeach()
199  set(${OUT} "${${OUT}}" PARENT_SCOPE)
200endfunction()
201
202function(csharp_get_filename_key_base base key)
203  get_filename_component(dir ${key} DIRECTORY)
204  get_filename_component(fil ${key} NAME_WE)
205  set(${base} "${dir}/${fil}" PARENT_SCOPE)
206endfunction()
207
208function(csharp_get_dependentupon_name out in)
209  get_filename_component(${out} ${in} NAME)
210  set(${out} ${${out}} PARENT_SCOPE)
211endfunction()
212
213function(csharp_set_windows_forms_properties)
214  csharp_get_filename_keys(fileKeys ${ARGN})
215  foreach(key ${fileKeys})
216    get_filename_component(ext ${key} EXT)
217    if(${ext} STREQUAL ".DESIGNER.CS" OR
218       ${ext} STREQUAL ".RESX")
219      csharp_get_filename_key_base(NAME_BASE ${key})
220      list(FIND fileKeys "${NAME_BASE}.CS" FILE_INDEX)
221      if(NOT ${FILE_INDEX} EQUAL -1)
222        list(GET ARGN ${FILE_INDEX} FILE_NAME)
223        # set properties of main form file
224        set_source_files_properties("${FILE_NAME}"
225          PROPERTIES
226          VS_CSHARP_SubType "Form")
227        csharp_get_dependentupon_name(LINK "${FILE_NAME}")
228        # set properties of designer file (if found)
229        list(FIND fileKeys "${NAME_BASE}.DESIGNER.CS" FILE_INDEX)
230        if(NOT ${FILE_INDEX} EQUAL -1)
231          list(GET ARGN ${FILE_INDEX} FILE_NAME)
232          set_source_files_properties("${FILE_NAME}"
233            PROPERTIES
234            VS_CSHARP_DependentUpon "${LINK}"
235            VS_CSHARP_DesignTime ""
236            VS_CSHARP_AutoGen "")
237        endif()
238        # set properties of corresponding resource file (if found)
239        list(FIND fileKeys "${NAME_BASE}.RESX" FILE_INDEX)
240        if(NOT ${FILE_INDEX} EQUAL -1)
241          list(GET ARGN ${FILE_INDEX} FILE_NAME)
242          set_source_files_properties("${FILE_NAME}"
243            PROPERTIES
244            VS_RESOURCE_GENERATOR ""
245            VS_CSHARP_DependentUpon "${LINK}"
246            VS_CSHARP_SubType "Designer")
247        endif()
248      endif()
249    endif()
250  endforeach()
251endfunction()
252
253function(csharp_set_designer_cs_properties)
254  csharp_get_filename_keys(fileKeys ${ARGN})
255  set(INDEX -1)
256  foreach(key ${fileKeys})
257    math(EXPR INDEX "${INDEX}+1")
258    list(GET ARGN ${INDEX} source)
259    get_filename_component(ext ${key} EXT)
260    if(${ext} STREQUAL ".DESIGNER.CS")
261      csharp_get_filename_key_base(NAME_BASE ${key})
262      if("${NAME_BASE}.RESX" IN_LIST fileKeys)
263        list(FIND fileKeys "${NAME_BASE}.RESX" FILE_INDEX)
264        list(GET ARGN ${FILE_INDEX} FILE_NAME)
265        csharp_get_dependentupon_name(LINK "${FILE_NAME}")
266        set_source_files_properties("${source}"
267          PROPERTIES
268          VS_CSHARP_AutoGen "True"
269          VS_CSHARP_DesignTime "True"
270          VS_CSHARP_DependentUpon "${LINK}")
271      elseif("${NAME_BASE}.CS" IN_LIST fileKeys)
272        list(FIND fileKeys "${NAME_BASE}.CS" FILE_INDEX)
273        list(GET ARGN ${FILE_INDEX} FILE_NAME)
274        csharp_get_dependentupon_name(LINK "${FILE_NAME}")
275        set_source_files_properties("${source}"
276          PROPERTIES
277          VS_CSHARP_DependentUpon "${LINK}")
278      elseif("${NAME_BASE}.SETTINGS" IN_LIST fileKeys)
279        list(FIND fileKeys "${NAME_BASE}.SETTINGS" FILE_INDEX)
280        list(GET ARGN ${FILE_INDEX} FILE_NAME)
281        csharp_get_dependentupon_name(LINK "${FILE_NAME}")
282        set_source_files_properties("${source}"
283          PROPERTIES
284          VS_CSHARP_AutoGen "True"
285          VS_CSHARP_DesignTimeSharedInput "True"
286          VS_CSHARP_DependentUpon "${LINK}")
287      endif()
288    endif()
289  endforeach()
290endfunction()
291
292function(csharp_set_xaml_cs_properties)
293  csharp_get_filename_keys(fileKeys ${ARGN})
294  set(INDEX -1)
295  foreach(key ${fileKeys})
296    math(EXPR INDEX "${INDEX}+1")
297    list(GET ARGN ${INDEX} source)
298    get_filename_component(ext ${key} EXT)
299    if(${ext} STREQUAL ".XAML.CS")
300      csharp_get_filename_key_base(NAME_BASE ${key})
301      if("${NAME_BASE}.XAML" IN_LIST fileKeys)
302        list(FIND fileKeys "${NAME_BASE}.XAML" FILE_INDEX)
303        list(GET ARGN ${FILE_INDEX} FILE_NAME)
304        csharp_get_dependentupon_name(LINK "${FILE_NAME}")
305        set_source_files_properties("${source}"
306          PROPERTIES
307          VS_CSHARP_DependentUpon "${LINK}")
308      endif()
309    endif()
310  endforeach()
311endfunction()
312
313cmake_policy(POP)
314