Skip to content

Commit 70eb61c

Browse files
authored
Merge pull request #731 from zillemarco/master
CLI improvements
2 parents f1ec084 + 06491bb commit 70eb61c

File tree

4 files changed

+120
-65
lines changed

4 files changed

+120
-65
lines changed

src/CLI/CLI.cs

Lines changed: 95 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -10,65 +10,117 @@ namespace CppSharp
1010
class CLI
1111
{
1212
private static Options _options = new Options();
13-
private static List<string> _assemblies;
1413

1514
static void AddIncludeDirs(String dir)
1615
{
1716
_options.IncludeDirs.Add(dir);
1817
}
1918

20-
static void ParseCommandLineArgs(string[] args)
19+
static bool ParseCommandLineArgs(string[] args)
2120
{
22-
var showHelp = args.Length == 0;
21+
var showHelp = false;
2322

2423
var optionSet = new Mono.Options.OptionSet()
2524
{
26-
{ "h|header=", "the path to an header file to generate source from", h => _options.HeaderFiles.Add(h) },
27-
{ "pa|path=", "the path of a folder whose files will generate code (can append a filter at the end like '<path>/*.hpp'", pa => { GetFilesFromPath(pa); } },
28-
{ "inc|includedir=", "the path of a folder to search for include files", i => { AddIncludeDirs(i); } },
29-
{ "l|library=", "the path of a library that includes the definitions for the generated source code", l => _options.Libraries.Add(l) },
30-
{ "ld|librarydir=", "the path of a folder to search for additional libraries", l => _options.LibraryDirs.Add(l) },
31-
{ "d|define=", "a define to add for the parse of the given header files", d => _options.Defines.Add(d) },
32-
{ "od|outputdir=", "the path for the destination folder that will contain the generated code", od => _options.OutputDir = od },
33-
{ "on|outputnamespace=", "the namespace that will be used for the generated code", on => _options.OutputNamespace = on },
34-
{ "iln|inputlibraryname=", "the name of the shared library that contains the actual definitions (without extension)", iln => _options.InputLibraryName = iln },
35-
{ "isln|inputsharedlibraryname=", "the full name of the shared library that contains the actual definitions (with extension)", isln => _options.InputSharedLibraryName = isln },
36-
{ "gen|generator=", "the type of generated code: 'chsarp' or 'cli' ('cli' supported only for Windows)", g => { GetGeneratorKind(g); } },
37-
{ "p|platform=", "the platform that the generated code will target: 'win', 'osx', 'linux'", p => { GetDestinationPlatform(p); } },
38-
{ "a|arch=", "the architecture that the generated code will target: 'x86', 'x64'", a => { GetDestinationArchitecture(a); } },
25+
{ "I=", "the {PATH} of a folder to search for include files", i => { AddIncludeDirs(i); } },
26+
{ "l=", "{LIBRARY} that that contains the symbols of the generated code", l => _options.Libraries.Add(l) },
27+
{ "L=", "the {PATH} of a folder to search for additional libraries", l => _options.LibraryDirs.Add(l) },
28+
{ "D:", "additional define with (optional) value to add to be used while parsing the given header files", (n, v) => AddDefine(n, v) },
29+
30+
{ "o=|output=", "the {PATH} for the generated bindings file (doesn't need the extension since it will depend on the generator)", v => HandleOutputArg(v) },
31+
{ "on=|outputnamespace=", "the {NAMESPACE} that will be used for the generated code", on => _options.OutputNamespace = on },
32+
33+
{ "iln=|inputlibraryname=", "the {NAME} of the shared library that contains the symbols of the generated code", iln => _options.InputLibraryName = iln },
34+
35+
{ "g=|gen=|generator=", "the {TYPE} of generated code: 'chsarp' or 'cli' ('cli' supported only for Windows)", g => { GetGeneratorKind(g); } },
36+
{ "p=|platform=", "the {PLATFORM} that the generated code will target: 'win', 'osx' or 'linux'", p => { GetDestinationPlatform(p); } },
37+
{ "a=|arch=", "the {ARCHITECTURE} that the generated code will target: 'x86' or 'x64'", a => { GetDestinationArchitecture(a); } },
38+
3939
{ "c++11", "enables GCC C++ 11 compilation (valid only for Linux platform)", cpp11 => { _options.Cpp11ABI = (cpp11 != null); } },
4040
{ "cs|checksymbols", "enable the symbol check for the generated code", cs => { _options.CheckSymbols = (cs != null); } },
4141
{ "ub|unitybuild", "enable unity build", ub => { _options.UnityBuild = (ub != null); } },
42-
{ "help", "shows the help", hl => { showHelp = (hl != null); } }
42+
43+
{ "h|help", "shows the help", hl => { showHelp = (hl != null); } },
4344
};
44-
45+
46+
List<String> additionalArguments = null;
47+
4548
try
4649
{
47-
_assemblies = optionSet.Parse(args);
50+
additionalArguments = optionSet.Parse(args);
4851
}
4952
catch (Mono.Options.OptionException e)
5053
{
5154
Console.WriteLine(e.Message);
52-
Environment.Exit(0);
55+
return false;
5356
}
54-
55-
if (showHelp)
57+
58+
if (showHelp || additionalArguments != null && additionalArguments.Count == 0)
5659
{
57-
// Print usage and exit.
58-
Console.WriteLine("{0} [options]+", AppDomain.CurrentDomain.FriendlyName);
59-
Console.WriteLine("Generates target language bindings for interop with unmanaged code.");
60-
Console.WriteLine();
61-
optionSet.WriteOptionDescriptions(Console.Out);
62-
Environment.Exit(0);
60+
ShowHelp(optionSet);
61+
return false;
6362
}
6463

65-
if (_assemblies == null)
64+
foreach(String s in additionalArguments)
65+
HandleAdditionalArgument(s);
66+
67+
return true;
68+
}
69+
70+
static void ShowHelp(Mono.Options.OptionSet options)
71+
{
72+
Console.WriteLine("Usage: {0} [options]+", AppDomain.CurrentDomain.FriendlyName);
73+
Console.WriteLine("Generates target language bindings to interop with unmanaged code.");
74+
Console.WriteLine();
75+
Console.WriteLine("Options:");
76+
options.WriteOptionDescriptions(Console.Out);
77+
Console.WriteLine();
78+
Console.WriteLine();
79+
Console.WriteLine("Useful informations:");
80+
Console.WriteLine(" - the options 'iln' (same as 'inputlibraryname') and 'l' have a similar meaning. Both of them are used to tell");
81+
Console.WriteLine(" the generator which library has to be used to P/Invoke the functions from your native code.");
82+
Console.WriteLine(" The difference is that if you want to generate the bindings for more than one library within a single managed");
83+
Console.WriteLine(" file you need to use the 'l' option to specify the names of all the libraries that contain the symbols to be loaded");
84+
Console.WriteLine(" and you MUST set the 'cs' ('checksymbols') flag to let the generator automatically understand which library");
85+
Console.WriteLine(" to use to P/Invoke. This can be also used if you plan to generate the bindings for only one library.");
86+
Console.WriteLine(" If you specify the 'iln' (or 'inputlibraryname') options, this option's value will be used for all the P/Invokes");
87+
Console.WriteLine(" that the generator will create.");
88+
Console.WriteLine(" - If you specify the 'unitybuild' option then the generator will output a file for each given header file that will");
89+
Console.WriteLine(" contain only the bindings for that header file.");
90+
}
91+
92+
static void HandleOutputArg(String arg)
93+
{
94+
try
95+
{
96+
String dir = System.IO.Path.GetDirectoryName(arg);
97+
String file = System.IO.Path.GetFileNameWithoutExtension(arg);
98+
99+
_options.OutputDir = dir;
100+
_options.OutputFileName = file;
101+
}
102+
catch(Exception e)
66103
{
67-
Console.WriteLine("Invalid arguments.");
104+
Console.WriteLine("Output error: " + e.Message);
68105
Environment.Exit(0);
69106
}
70107
}
71108

109+
static void AddDefine(String name, String value)
110+
{
111+
if (name == null)
112+
throw new Mono.Options.OptionException("Invalid definition name for option -D.", "-D");
113+
_options.Defines.Add(name, value);
114+
}
115+
116+
static void HandleAdditionalArgument(String args)
117+
{
118+
if (System.IO.Directory.Exists(args))
119+
GetFilesFromPath(args);
120+
else if (System.IO.File.Exists(args))
121+
_options.HeaderFiles.Add(args);
122+
}
123+
72124
static void GetFilesFromPath(String path)
73125
{
74126
path = path.Replace(System.IO.Path.DirectorySeparatorChar, System.IO.Path.AltDirectorySeparatorChar);
@@ -115,10 +167,10 @@ static void GetGeneratorKind(String generator)
115167
{
116168
case "csharp":
117169
_options.Kind = CppSharp.Generators.GeneratorKind.CSharp;
118-
break;
170+
return;
119171
case "cli":
120172
_options.Kind = CppSharp.Generators.GeneratorKind.CLI;
121-
break;
173+
return;
122174
}
123175

124176
throw new NotSupportedException("Unknown generator kind: " + generator);
@@ -130,13 +182,13 @@ static void GetDestinationPlatform(String platform)
130182
{
131183
case "win":
132184
_options.Platform = TargetPlatform.Windows;
133-
break;
185+
return;
134186
case "osx":
135187
_options.Platform = TargetPlatform.MacOS;
136-
break;
188+
return;
137189
case "linux":
138190
_options.Platform = TargetPlatform.Linux;
139-
break;
191+
return;
140192
}
141193

142194
throw new NotSupportedException("Unknown target platform: " + platform);
@@ -148,28 +200,28 @@ static void GetDestinationArchitecture(String architecture)
148200
{
149201
case "x86":
150202
_options.Architecture = TargetArchitecture.x86;
151-
break;
203+
return;
152204
case "x64":
153-
_options.Architecture = TargetArchitecture.x64;
154-
break;
205+
_options.Architecture = TargetArchitecture.x64;
206+
return;
155207
}
156208

157209
throw new NotSupportedException("Unknown target architecture: " + architecture);
158210
}
159211

160212
static void Main(string[] args)
161213
{
162-
ParseCommandLineArgs(args);
163-
164-
Generator gen = new Generator(_options);
165-
166214
try
167215
{
216+
if (ParseCommandLineArgs(args) == false)
217+
return;
218+
219+
Generator gen = new Generator(_options);
168220
gen.Run();
169221
}
170222
catch (Exception ex)
171223
{
172-
Console.WriteLine("Error: " + ex.ToString());
224+
Console.WriteLine(ex.Message);
173225
}
174226
}
175227
}

src/CLI/Generator.cs

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,14 @@ public void ValidateOptions()
4646
if (_options.OutputNamespace == String.Empty)
4747
throw new NotSupportedException("Output namespace is empty");
4848

49-
if (_options.InputLibraryName == String.Empty)
50-
throw new NotSupportedException("Input library name is empty");
49+
if (_options.OutputFileName == String.Empty)
50+
throw new NotSupportedException("Output not specified");
51+
52+
if(_options.InputLibraryName == String.Empty && _options.CheckSymbols == false)
53+
throw new NotSupportedException("Input library name not specified and check symbols not enabled. Either set the input library name or the check symbols flag");
54+
55+
if(_options.InputLibraryName == String.Empty && _options.CheckSymbols == true && _options.Libraries.Count == 0)
56+
throw new NotSupportedException("Input library name not specified and check symbols is enabled but no libraries were given. Either set the input library name or add at least one library");
5157

5258
if (_options.Architecture == TargetArchitecture.x64)
5359
_triple = "x86_64-";
@@ -81,10 +87,10 @@ public void Setup(Driver driver)
8187
parserOptions.Abi = _abi;
8288

8389
var options = driver.Options;
84-
options.LibraryName = _options.InputLibraryName;
90+
options.LibraryName = _options.OutputFileName;
8591

86-
if(_options.InputSharedLibraryName != String.Empty)
87-
options.SharedLibraryName = _options.InputSharedLibraryName;
92+
if(_options.InputLibraryName != String.Empty)
93+
options.SharedLibraryName = _options.InputLibraryName;
8894

8995
options.GeneratorKind = _options.Kind;
9096
options.Headers.AddRange(_options.HeaderFiles);
@@ -98,20 +104,20 @@ public void Setup(Driver driver)
98104

99105
if (_triple.Contains("linux"))
100106
SetupLinuxOptions(parserOptions);
101-
102-
Console.WriteLine("\n\nAdding " + (_options.IncludeDirs.Count) + " include dirs\n\n");
103-
107+
104108
foreach (String s in _options.IncludeDirs)
105-
{
106109
parserOptions.AddIncludeDirs(s);
107-
Console.WriteLine("Add include: " + s);
108-
}
109110

110111
foreach (String s in _options.LibraryDirs)
111112
parserOptions.AddLibraryDirs(s);
112113

113-
foreach (String s in _options.Defines)
114-
parserOptions.AddDefines(s);
114+
foreach (KeyValuePair<String, String> d in _options.Defines)
115+
{
116+
if(d.Value == null || d.Value == String.Empty)
117+
parserOptions.AddDefines(d.Key);
118+
else
119+
parserOptions.AddDefines(d.Key + "=" + d.Value);
120+
}
115121

116122
options.OutputDir = _options.OutputDir;
117123
options.OutputNamespace = _options.OutputNamespace;

src/CLI/Options.cs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,21 +35,21 @@ class Options
3535
private List<String> _libraries = new List<string>();
3636
public List<String> Libraries { get { return _libraries; } set { _libraries = value; } }
3737

38-
private List<String> _defines = new List<string>();
39-
public List<String> Defines { get { return _defines; } set { _defines = value; } }
38+
private Dictionary<String, String> _defines = new Dictionary<String, String>();
39+
public Dictionary<String, String> Defines { get { return _defines; } set { _defines = value; } }
4040

4141
private String _outputDir = "";
4242
public String OutputDir { get { return _outputDir; } set { _outputDir = value; } }
4343

4444
private String _outputNamespace = "";
4545
public String OutputNamespace { get { return _outputNamespace; } set { _outputNamespace = value; } }
4646

47+
private String _outputFileName = "";
48+
public String OutputFileName { get { return _outputFileName; } set { _outputFileName = value; } }
49+
4750
private String _inputLibraryName = "";
4851
public String InputLibraryName { get { return _inputLibraryName; } set { _inputLibraryName = value; } }
4952

50-
private String _inputSharedLibraryName = "";
51-
public String InputSharedLibraryName { get { return _inputSharedLibraryName; } set { _inputSharedLibraryName = value; } }
52-
5353
private String _triple = "";
5454
public String Triple { get { return _triple; } set { _triple = value; } }
5555

@@ -62,9 +62,6 @@ class Options
6262
private GeneratorKind _kind = GeneratorKind.CSharp;
6363
public GeneratorKind Kind { get { return _kind; } set { _kind = value; } }
6464

65-
//private bool _verbose = false;
66-
//public bool Verbose { get { return _verbose; } set { _verbose = value; } }
67-
6865
private bool _checkSymbols = false;
6966
public bool CheckSymbols { get { return _checkSymbols; } set { _checkSymbols = value; } }
7067

src/CLI/premake5.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ project "CppSharp.CLI"
22

33
SetupManagedProject()
44

5-
kind "SharedLib"
5+
kind "ConsoleApp"
66
language "C#"
77

88
files { "**.cs" }

0 commit comments

Comments
 (0)