Skip to content

Commit 4972bc4

Browse files
authored
Add CMake generator for Interop skeleton (#58)
1 parent 060e2f5 commit 4972bc4

File tree

5 files changed

+137
-34
lines changed

5 files changed

+137
-34
lines changed

source/MetadataProcessor.Core/MetadataProcessor.Core.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@
9090
<Compile Include="nanoSkeletonGenerator.cs" />
9191
<Compile Include="SkeletonGenerator\AssemblyClass.cs" />
9292
<Compile Include="SkeletonGenerator\AssemblyClassStubs.cs" />
93+
<Compile Include="SkeletonGenerator\AssemblyClassTable.cs" />
9394
<Compile Include="SkeletonGenerator\AssemblyLookupTable.cs" />
9495
<Compile Include="Tables\ICustomStringSorter.cs" />
9596
<Compile Include="Tables\nanoAssemblyReferenceTable.cs" />

source/MetadataProcessor.Core/SkeletonGenerator/AssemblyClassStubs.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ public class AssemblyClassStubs
2121

2222
public string ProjectName;
2323

24+
public string AssemblyName;
25+
2426
public List<MethodStub> Functions = new List<MethodStub>();
2527
}
2628
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//
2+
// Copyright (c) 2019 The nanoFramework project contributors
3+
// See LICENSE file in the project root for full license information.
4+
//
5+
6+
using System.Collections.Generic;
7+
8+
namespace nanoFramework.Tools.MetadataProcessor.Core
9+
{
10+
public class AssemblyClassTable
11+
{
12+
public string AssemblyName;
13+
public string HeaderFileName;
14+
public string ProjectName;
15+
16+
public List<Class> Classes = new List<Class>();
17+
}
18+
}

source/MetadataProcessor.Core/SkeletonGenerator/SkeletonTemplates.cs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,5 +235,56 @@ struct {{ClassName}}
235235
NANOCLR_NOCLEANUP();
236236
}
237237
{{/each}}";
238+
239+
internal const string CMakeModuleTemplate =
240+
@"#
241+
# Copyright(c) 2018 The nanoFramework project contributors
242+
# See LICENSE file in the project root for full license information.
243+
#
244+
245+
#################################################################################################
246+
# make sure that a valid path is set bellow #
247+
# if this is for a class library it's OK to leave it as it is #
248+
# if this is an Interop module the path has to be set where the build can find the source files #
249+
#################################################################################################
250+
251+
# native code directory
252+
set(BASE_PATH_FOR_THIS_MODULE ${BASE_PATH_FOR_CLASS_LIBRARIES_MODULES}/{{AssemblyName}})
253+
254+
255+
# set include directories
256+
list(APPEND {{AssemblyName}}_INCLUDE_DIRS ${PROJECT_SOURCE_DIR}/src/CLR/Core)
257+
list(APPEND {{AssemblyName}}_INCLUDE_DIRS ${PROJECT_SOURCE_DIR}/src/CLR/Include)
258+
list(APPEND {{AssemblyName}}_INCLUDE_DIRS ${PROJECT_SOURCE_DIR}/src/HAL/Include)
259+
list(APPEND {{AssemblyName}}_INCLUDE_DIRS ${PROJECT_SOURCE_DIR}/src/PAL/Include)
260+
list(APPEND {{AssemblyName}}_INCLUDE_DIRS ${BASE_PATH_FOR_THIS_MODULE})
261+
262+
# source files
263+
set({{AssemblyName}}_SRCS
264+
{{HeaderFileName}}.cpp
265+
{{#each Classes}}
266+
{{HeaderFileName}}_{{Name}}_mshl.cpp
267+
{{HeaderFileName}}_{{Name}}.cpp{{/each}}
268+
269+
)
270+
271+
foreach(SRC_FILE ${{{AssemblyName}}_SRCS})
272+
273+
set({{AssemblyName}}_SRC_FILE SRC_FILE-NOTFOUND)
274+
find_file({{AssemblyName}}_SRC_FILE ${ SRC_FILE}
275+
PATHS
276+
""${BASE_PATH_FOR_THIS_MODULE}""
277+
""${TARGET_BASE_LOCATION}""
278+
279+
CMAKE_FIND_ROOT_PATH_BOTH
280+
)
281+
# message(""${SRC_FILE} >> ${{{AssemblyName}}_SRC_FILE}"") # debug helper
282+
list(APPEND {{AssemblyName}}_SOURCES ${{{AssemblyName}}_SRC_FILE})
283+
endforeach()
284+
285+
include(FindPackageHandleStandardArgs)
286+
287+
FIND_PACKAGE_HANDLE_STANDARD_ARGS({{AssemblyName}} DEFAULT_MSG {{AssemblyName}}_INCLUDE_DIRS {{AssemblyName}}_SOURCES)
288+
";
238289
}
239290
}

source/MetadataProcessor.Core/nanoSkeletonGenerator.cs

Lines changed: 65 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ public sealed class nanoSkeletonGenerator
2424
private readonly string _project;
2525
private readonly bool _withoutInteropCode;
2626
private readonly bool _isCoreLib;
27-
private string _assemblyName;
27+
private readonly string _assemblyName;
28+
29+
private string _safeProjectName => _project.Replace('.', '_');
2830

2931
public nanoSkeletonGenerator(
3032
nanoTablesContext tablesContext,
@@ -40,13 +42,13 @@ public nanoSkeletonGenerator(
4042
_project = project;
4143
_withoutInteropCode = withoutInteropCode;
4244
_isCoreLib = isCoreLib;
43-
}
4445

45-
public void GenerateSkeleton()
46-
{
4746
// replaces "." with "_" so the assembly name can be part of C++ identifier name
4847
_assemblyName = _name.Replace('.', '_');
48+
}
4949

50+
public void GenerateSkeleton()
51+
{
5052
// create <assembly>.h with the structs declarations
5153
GenerateAssemblyHeader();
5254

@@ -59,38 +61,48 @@ public void GenerateSkeleton()
5961

6062
private void GenerateStubs()
6163
{
64+
var classList = new AssemblyClassTable
65+
{
66+
AssemblyName = _tablesContext.AssemblyDefinition.Name.Name,
67+
ProjectName = _safeProjectName
68+
};
69+
6270
foreach (var c in _tablesContext.TypeDefinitionTable.TypeDefinitions)
6371
{
6472
if (c.IncludeInStub() &&
6573
!c.IsClassToExclude())
6674
{
6775
var className = NativeMethodsCrc.GetClassName(c);
6876

69-
var classStubs = new AssemblyClassStubs();
77+
var classStubs = new AssemblyClassStubs
78+
{
79+
AssemblyName = _name,
80+
ClassHeaderFileName = className,
81+
ClassName = c.Name,
82+
ShortNameUpper = $"{_assemblyName}_{_safeProjectName}_{className}".ToUpper(),
83+
RootNamespace = _assemblyName,
84+
ProjectName = _safeProjectName
85+
};
7086

7187
if (!_withoutInteropCode)
7288
{
7389
// Interop code needs to use the root namespace
7490

75-
classStubs.HeaderFileName = $"{_assemblyName}_{_project}";
76-
classStubs.ClassHeaderFileName = className;
77-
classStubs.ClassName = c.Name;
78-
classStubs.ShortNameUpper = $"{_assemblyName}_{_project}_{className}".ToUpper();
79-
classStubs.RootNamespace = _assemblyName;
80-
classStubs.ProjectName = _project;
91+
classStubs.HeaderFileName = $"{_assemblyName}_{_safeProjectName}";
8192
}
8293
else
8394
{
8495
// projects with Interop can use a simplified naming
8596

86-
classStubs.HeaderFileName = _project;
87-
classStubs.ClassHeaderFileName = className;
88-
classStubs.ClassName = c.Name;
89-
classStubs.ShortNameUpper = $"{_assemblyName}_{_project}_{className}".ToUpper();
90-
classStubs.RootNamespace = _assemblyName;
91-
classStubs.ProjectName = _project;
97+
classStubs.HeaderFileName = _safeProjectName;
9298
}
9399

100+
classList.Classes.Add(new Class()
101+
{
102+
Name = className
103+
});
104+
classList.HeaderFileName = classStubs.HeaderFileName;
105+
94106
foreach (var m in nanoTablesContext.GetOrderedMethods(c.Methods))
95107
{
96108
var rva = _tablesContext.ByteCodeTable.GetMethodRva(m);
@@ -101,7 +113,7 @@ private void GenerateStubs()
101113
{
102114
var newMethod = new MethodStub()
103115
{
104-
Declaration = $"Library_{_project}_{className}::{NativeMethodsCrc.GetMethodName(m)}"
116+
Declaration = $"Library_{_safeProjectName}_{className}::{NativeMethodsCrc.GetMethodName(m)}"
105117
};
106118

107119
if(!_withoutInteropCode)
@@ -213,7 +225,7 @@ private void GenerateStubs()
213225
};
214226
Generator generator = compiler.Compile(SkeletonTemplates.ClassWithoutInteropStubTemplate);
215227

216-
using (var headerFile = File.CreateText(Path.Combine(_path, $"{_project}_{className}.cpp")))
228+
using (var headerFile = File.CreateText(Path.Combine(_path, $"{_safeProjectName}_{className}.cpp")))
217229
{
218230
var output = generator.Render(classStubs);
219231
headerFile.Write(output);
@@ -229,7 +241,7 @@ private void GenerateStubs()
229241
// user code stub
230242
Generator generator = compiler.Compile(SkeletonTemplates.ClassStubTemplate);
231243

232-
using (var headerFile = File.CreateText(Path.Combine(_path, $"{_assemblyName}_{_project}_{className}.cpp")))
244+
using (var headerFile = File.CreateText(Path.Combine(_path, $"{_assemblyName}_{_safeProjectName}_{className}.cpp")))
233245
{
234246
var output = generator.Render(classStubs);
235247
headerFile.Write(output);
@@ -238,7 +250,7 @@ private void GenerateStubs()
238250
// marshal code
239251
generator = compiler.Compile(SkeletonTemplates.ClassMarshallingCodeTemplate);
240252

241-
using (var headerFile = File.CreateText(Path.Combine(_path, $"{_assemblyName}_{_project}_{className}_mrsh.cpp")))
253+
using (var headerFile = File.CreateText(Path.Combine(_path, $"{_assemblyName}_{_safeProjectName}_{className}_mshl.cpp")))
242254
{
243255
var output = generator.Render(classStubs);
244256
headerFile.Write(output);
@@ -247,7 +259,7 @@ private void GenerateStubs()
247259
// class header
248260
generator = compiler.Compile(SkeletonTemplates.ClassHeaderTemplate);
249261

250-
using (var headerFile = File.CreateText(Path.Combine(_path, $"{_assemblyName}_{_project}_{className}.h")))
262+
using (var headerFile = File.CreateText(Path.Combine(_path, $"{_assemblyName}_{_safeProjectName}_{className}.h")))
251263
{
252264
var output = generator.Render(classStubs);
253265
headerFile.Write(output);
@@ -256,6 +268,25 @@ private void GenerateStubs()
256268
}
257269
}
258270
}
271+
272+
if (!_withoutInteropCode &&
273+
classList.Classes.Count > 0)
274+
{
275+
FormatCompiler compiler = new FormatCompiler
276+
{
277+
RemoveNewLines = false
278+
};
279+
280+
// CMake module
281+
Generator generator = compiler.Compile(SkeletonTemplates.CMakeModuleTemplate);
282+
283+
// FindINTEROP-NF.AwesomeLib
284+
using (var headerFile = File.CreateText(Path.Combine(_path, $"FindINTEROP-{_safeProjectName}.cmake")))
285+
{
286+
var output = generator.Render(classList);
287+
headerFile.Write(output);
288+
}
289+
}
259290
}
260291

261292
private void GenerateAssemblyLookup()
@@ -269,7 +300,7 @@ private void GenerateAssemblyLookup()
269300
IsCoreLib = _isCoreLib,
270301
Name = _name,
271302
AssemblyName = _assemblyName,
272-
HeaderFileName = _project,
303+
HeaderFileName = _safeProjectName,
273304
NativeVersion = nativeVersion,
274305
NativeCRC32 = "0x" + _tablesContext.NativeMethodsCrc.Current.ToString("X")
275306
};
@@ -298,7 +329,7 @@ private void GenerateAssemblyLookup()
298329
{
299330
assemblyLookup.LookupTable.Add(new MethodStub()
300331
{
301-
Declaration = $"Library_{_project}_{className}::{NativeMethodsCrc.GetMethodName(m)}"
332+
Declaration = $"Library_{_safeProjectName}_{className}::{NativeMethodsCrc.GetMethodName(m)}"
302333
});
303334
}
304335
else
@@ -312,7 +343,7 @@ private void GenerateAssemblyLookup()
312343
assemblyLookup.LookupTable.Add(new MethodStub()
313344
{
314345
Declaration = "NULL"
315-
//Declaration = $"**Library_{_project}_{NativeMethodsCrc.GetClassName(c)}::{NativeMethodsCrc.GetMethodName(m)}"
346+
//Declaration = $"**Library_{_safeProjectName}_{NativeMethodsCrc.GetClassName(c)}::{NativeMethodsCrc.GetMethodName(m)}"
316347
});
317348
}
318349
}
@@ -332,7 +363,7 @@ private void GenerateAssemblyLookup()
332363
assemblyLookup.LookupTable.Add(new MethodStub()
333364
{
334365
Declaration = "NULL"
335-
//Declaration = $"**Library_{_project}_{NativeMethodsCrc.GetClassName(c)}::{NativeMethodsCrc.GetMethodName(m)}"
366+
//Declaration = $"**Library_{_safeProjectName}_{NativeMethodsCrc.GetClassName(c)}::{NativeMethodsCrc.GetMethodName(m)}"
336367
});
337368
}
338369
}
@@ -347,12 +378,12 @@ private void GenerateAssemblyLookup()
347378
if (!_withoutInteropCode)
348379
{
349380
// Interop code needs to use the root namespace
350-
filePath = Path.Combine(_path, $"{_assemblyName}_{_project}.cpp");
381+
filePath = Path.Combine(_path, $"{_assemblyName}_{_safeProjectName}.cpp");
351382
}
352383
else
353384
{
354385
// projects with Interop can use a simplified naming
355-
filePath = Path.Combine(_path, $"{_project}.cpp");
386+
filePath = Path.Combine(_path, $"{_safeProjectName}.cpp");
356387
}
357388

358389
using (var headerFile = File.CreateText(filePath))
@@ -368,9 +399,9 @@ private void GenerateAssemblyHeader()
368399

369400
var assemblyData = new AssemblyDeclaration()
370401
{
371-
Name = _name.Replace('.', '_'),
372-
ShortName = _project,
373-
ShortNameUpper = _project.ToUpperInvariant(),
402+
Name = _assemblyName,
403+
ShortName = _safeProjectName,
404+
ShortNameUpper = _safeProjectName.ToUpperInvariant(),
374405
IsCoreLib = _isCoreLib
375406
};
376407

@@ -381,7 +412,7 @@ private void GenerateAssemblyHeader()
381412
{
382413
var classData = new Class()
383414
{
384-
AssemblyName = _project,
415+
AssemblyName = _safeProjectName,
385416
Name = NativeMethodsCrc.GetClassName(c)
386417
};
387418

@@ -480,12 +511,12 @@ private void GenerateAssemblyHeader()
480511
if (!_withoutInteropCode)
481512
{
482513
// Interop code needs to use the root namespace
483-
filePath = Path.Combine(_path, $"{_assemblyName}_{_project}.h");
514+
filePath = Path.Combine(_path, $"{_assemblyName}_{_safeProjectName}.h");
484515
}
485516
else
486517
{
487518
// projects with Interop can use a simplified naming
488-
filePath = Path.Combine(_path, $"{_project}.h");
519+
filePath = Path.Combine(_path, $"{_safeProjectName}.h");
489520
}
490521

491522
using (var headerFile = File.CreateText(filePath))

0 commit comments

Comments
 (0)