.NET Bindings: Add netmaker (.NET codemaker)

This commit adds the netmaker executable to the codemaker/ module, to
generate C# code from UNOIDL specifications.

Also adds some Makefiles in the net_ure/ directory to generate code for
udkapi and offapi, to build the net_uretypes and net_oootypes assemblies.

Change-Id: Ifb61fe6a0f8f594eaa6ff95b025ba57f247b0d4b
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/168710
Tested-by: Jenkins
Tested-by: Hossein <hossein@libreoffice.org>
Reviewed-by: Hossein <hossein@libreoffice.org>
This commit is contained in:
RMZeroFour 2024-06-12 13:56:05 +05:30 committed by Hossein
parent 64365dfa67
commit e597e712b6
17 changed files with 1807 additions and 12 deletions

View file

@ -92,6 +92,7 @@ $(eval $(call gb_Helper_register_executables_for_install,SDK,sdk, \
$(if $(filter MSC,$(COM)),$(if $(filter-out AARCH64_TRUE,$(CPUNAME)_$(CROSS_COMPILING)),climaker)) \
cppumaker \
javamaker \
netmaker \
$(call gb_CondExeSp2bv,sp2bv) \
$(if $(filter ODK,$(BUILD_TYPE)),unoapploader) \
unoidl-read \

View file

@ -0,0 +1,28 @@
# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
#
# This file is part of the LibreOffice project.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
$(eval $(call gb_Executable_Executable,netmaker))
$(eval $(call gb_Executable_use_libraries,netmaker,\
salhelper \
sal \
unoidl \
))
$(eval $(call gb_Executable_use_static_libraries,netmaker,\
codemaker \
))
$(eval $(call gb_Executable_add_exception_objects,netmaker,\
codemaker/source/netmaker/netmaker \
codemaker/source/netmaker/netoptions \
codemaker/source/netmaker/netproduce \
))
# vim:set noet sw=4 ts=4:

View file

@ -17,6 +17,7 @@ $(eval $(call gb_Module_add_targets,codemaker,\
StaticLibrary_codemaker_java \
Executable_javamaker \
Executable_cppumaker \
Executable_netmaker \
))
endif

View file

@ -5,7 +5,8 @@ Generators for language-binding--specific representations of UNOIDL entities:
- `cppumaker` generates header (`.hdl` and `.hpp`) files for the C++ UNO language
binding
- `javamaker` generates class files for the JVM language binding
- the codemaker for .NET is in module `cli_ure`
- `netmaker` generates C# code files for the .NET language binding
- `climaker` (the old codemaker for .NET Framework) is in module `cli_ure`
Some of the code is re-used by the skeletonmakers in module `unodevtools`.

View file

@ -0,0 +1,105 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <filesystem>
#include <fstream>
#include <string>
#include <string_view>
class CSharpFile
{
public:
CSharpFile(std::string_view directory, std::string_view typeName)
: m_filePath(createFilePath(directory, typeName))
{
}
public:
std::string getPath() const { return m_filePath.string(); }
void openFile()
{
std::filesystem::create_directories(m_filePath.parent_path());
m_fileStream.open(m_filePath, std::fstream::out | std::fstream::trunc);
m_indentLevel = 0;
}
void closeFile() { m_fileStream.close(); }
CSharpFile& beginBlock()
{
beginLine();
append("{");
endLine();
++m_indentLevel;
return *this;
}
CSharpFile& endBlock()
{
--m_indentLevel;
beginLine();
append("}");
endLine();
return *this;
}
CSharpFile& beginLine()
{
for (int i = 0; i < m_indentLevel; i++)
{
m_fileStream << " ";
}
return *this;
}
CSharpFile& extraIndent()
{
m_fileStream << " ";
return *this;
}
CSharpFile& append(std::string_view item)
{
m_fileStream << item;
return *this;
}
CSharpFile& append(std::u16string_view item)
{
m_fileStream << u2b(item);
return *this;
}
CSharpFile& endLine()
{
m_fileStream << '\n';
return *this;
}
private:
static std::filesystem::path createFilePath(std::string_view dir, std::string_view type)
{
std::string subdir(type);
for (char& c : subdir)
if (c == '.')
c = '/';
std::filesystem::path path(dir);
path /= subdir + ".cs";
return path;
}
private:
std::filesystem::path m_filePath;
std::ofstream m_fileStream;
int m_indentLevel = 0;
};
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */

View file

@ -0,0 +1,60 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include <iostream>
#include <sal/main.h>
#include <unoidl/unoidl.hxx>
#include "netoptions.hxx"
#include "netproduce.hxx"
SAL_IMPLEMENT_MAIN_WITH_ARGS(argc, argv)
{
try
{
NetOptions options;
NetProducer producer;
if (options.initOptions(argc, argv))
{
producer.initProducer(options);
producer.produceAll();
}
}
catch (const ::IllegalArgument& e)
{
std::cerr << "ERROR: Illegal option " << e.m_message << '\n';
return EXIT_FAILURE;
}
catch (const ::CannotDumpException& e)
{
std::cerr << "ERROR: Could not dump as " << e.getMessage() << '\n';
return EXIT_FAILURE;
}
catch (const unoidl::NoSuchFileException& e)
{
std::cerr << "ERROR: No such file " << e.getUri() << '\n';
return EXIT_FAILURE;
}
catch (const unoidl::FileFormatException& e)
{
std::cerr << "ERROR: Bad format of " << e.getUri() << ", '" << e.getDetail() << "'\n";
return EXIT_FAILURE;
}
catch (const std::exception& e)
{
std::cerr << "ERROR: " << e.what() << '\n';
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */

View file

@ -0,0 +1,150 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include <iostream>
#include <string>
#include "netoptions.hxx"
// the third parameter, bCmdFile, is unimplemented and hence unused
bool NetOptions::initOptions(int argc, char* argv[], bool)
{
if (argc < 2)
{
std::cerr << prepareHelp();
return false;
}
for (int i = 1; i < argc; i++)
{
OString argument = argv[i];
if (argument == "-h"_ostr || argument == "--help"_ostr)
{
std::cout << prepareHelp();
return false;
}
else if (argument == "-v"_ostr || argument == "--verbose"_ostr)
{
m_options["--verbose"_ostr] = ""_ostr;
}
else if (argument == "-n"_ostr || argument == "--dry-run"_ostr)
{
m_options["--dry-run"_ostr] = ""_ostr;
// dry run implies verbose
m_options["--verbose"_ostr] = "--dry-run"_ostr;
}
else if (argument == "-T"_ostr || argument == "--types"_ostr)
{
if (i + 1 < argc)
{
if (m_options.count("--types"_ostr) == 0)
{
m_options["--types"_ostr] = argv[++i];
}
else
{
m_options["--types"_ostr] += ";"_ostr + argv[++i];
}
}
else
{
throw IllegalArgument("-T/--types must be followed by type name or wildcard"_ostr);
}
}
else if (argument == "-X"_ostr || argument == "--extra-types"_ostr)
{
if (i + 1 < argc)
{
m_extra_input_files.emplace_back(argv[++i]);
}
else
{
throw IllegalArgument("-X/--extra-types must be followed by .rdb file"_ostr);
}
}
else if (argument == "-O"_ostr || argument == "--output-dir"_ostr)
{
if (i + 1 < argc)
{
m_options["--output-dir"_ostr] = argv[++i];
}
else
{
throw IllegalArgument("-O/--output-dir must be followed by directory"_ostr);
}
}
else
{
m_inputFiles.emplace_back(argument);
}
}
if (m_inputFiles.empty())
{
throw IllegalArgument("at least one .rdb file must be provided"_ostr);
}
if (m_options.count("--output-dir"_ostr) == 0)
{
throw IllegalArgument("-O/--output-dir must be provided"_ostr);
}
return true;
}
OString NetOptions::prepareHelp()
{
return prepareVersion() + R"(
About:
netmaker is a tool for generating C# files from a type library generated by the UNOIDL compiler unoidl-write.
The generated code files require a reference to the net_basetypes.dll assembly to build.
Usage:
netmaker [-v|--verbose] [-n|--dry-run]
[-T|--types <type name or wildcard>]
[-X|--extra-types <.rdb file>]
-O|--output-dir <output directory>
<rdb file(s)>
Options:
-h, --help
Display this help message.
-v, --verbose
Log the name of every file created and type generated to stdout.
-n, --dry-run
Do not write generated files to disk. Implies --verbose.
-T, --types <type name or wildcard>
Specify a type name or a wildcard pattern to generate code for. This option can be specified multiple times. If not specified, all types in the given .rdb files are generated.
-X, --extra-types <.rdb file>
Use an .rdb file containing types to be taken into account without generating output for them. This option can be specified multiple times.
-O, --output-dir <directory>
Specify the directory to write generated files to.
Examples:
netmaker --verbose -T com.acme.XSomething \
-X types.rdb -O acme/ acmetypes.rdb
netmaker --dry-run -T com.acme.* -X types.rdb \
-X offapi.rdb -O acme/ acmetypes.rdb
netmaker -X types.rdb -O acme/ \
acmetypes.rdb moretypes.rdb
)"_ostr;
}
OString NetOptions::prepareVersion() const { return m_program + " version "_ostr + m_version; }
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */

View file

@ -0,0 +1,33 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <rtl/string.hxx>
#include <codemaker/options.hxx>
class NetOptions : public Options
{
public:
NetOptions()
{
m_program = "netmaker"_ostr;
m_version = "0.1.0"_ostr;
}
bool initOptions(int argc, char* argv[], bool bCmdFile = false) override;
OString prepareHelp() override;
OString prepareVersion() const;
private:
OString m_version;
};
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,69 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <unordered_set>
#include <string_view>
#include <codemaker/typemanager.hxx>
#include <rtl/string.hxx>
#include <unoidl/unoidl.hxx>
#include "netoptions.hxx"
class NetProducer
{
public:
NetProducer()
: m_manager(new TypeManager())
{
}
public:
void initProducer(const NetOptions& options);
void produceAll();
private:
void produceType(const OString& name);
void produceModule(std::string_view name, const rtl::Reference<unoidl::MapCursor>& cursor);
void produceEnum(std::string_view name, const rtl::Reference<unoidl::EnumTypeEntity>& entity);
void producePlainStruct(std::string_view name,
const rtl::Reference<unoidl::PlainStructTypeEntity>& entity);
void
producePolyStruct(std::string_view name,
const rtl::Reference<unoidl::PolymorphicStructTypeTemplateEntity>& entity);
void produceException(std::string_view name,
const rtl::Reference<unoidl::ExceptionTypeEntity>& entity);
void produceInterface(std::string_view name,
const rtl::Reference<unoidl::InterfaceTypeEntity>& entity);
void produceTypedef(std::string_view name, const rtl::Reference<unoidl::TypedefEntity>& entity);
void produceConstantGroup(std::string_view name,
const rtl::Reference<unoidl::ConstantGroupEntity>& entity);
void produceService(std::string_view name,
const rtl::Reference<unoidl::SingleInterfaceBasedServiceEntity>& entity);
void produceSingleton(std::string_view name,
const rtl::Reference<unoidl::InterfaceBasedSingletonEntity>& entity);
OString getNetName(std::string_view name);
OString getNetName(std::u16string_view name);
private:
rtl::Reference<TypeManager> m_manager;
std::unordered_set<OString> m_startingTypes;
std::unordered_set<OString> m_typesProduced;
std::unordered_map<OString, OString> m_typedefs;
OString m_outputDir;
bool m_verbose;
bool m_dryRun;
};
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */

View file

@ -0,0 +1,40 @@
# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
#
# This file is part of the LibreOffice project.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
$(eval $(call gb_CustomTarget_CustomTarget,net_oootypes))
net_ure_DIR := $(gb_CustomTarget_workdir)/net_ure
net_oootypes_DIR := $(gb_CustomTarget_workdir)/net_ure/net_oootypes
$(call gb_CustomTarget_get_target,net_oootypes) : $(net_ure_DIR)/net_oootypes.done
$(net_ure_DIR)/net_oootypes.done : \
$(call gb_UnoApi_get_target,offapi) \
$(call gb_UnoApi_get_target,udkapi) \
$(call gb_Executable_get_target,netmaker) \
$(call gb_Executable_get_runtime_dependencies,netmaker) \
| $(net_oootypes_DIR)/.dir
$(call gb_Output_announce,$(subst $(WORKDIR)/,,$@),$(true),NET,4)
$(call gb_Trace_StartRange,$(subst $(WORKDIR)/,,$@),NET)
$(call gb_Helper_abbreviate_dirs, \
rm -r $(net_oootypes_DIR) && \
$(call gb_Helper_execute,netmaker -v -O $(net_oootypes_DIR) \
-X $(call gb_UnoApi_get_target,udkapi) \
$(call gb_UnoApi_get_target,offapi) > $@.log 2>&1 || \
(echo \
&& cat $@.log \
&& echo \
&& echo "net_oootypes failed to generate. To retry, use:" \
&& echo " make CustomTarget_net_oootypes" \
&& echo "cd into the net_ure/ directory to run make faster" \
&& echo \
&& false)) && \
touch $@)
$(call gb_Trace_EndRange,$(subst $(WORKDIR)/,,$@),NET)
# vim: set noet sw=4 ts=4:

View file

@ -0,0 +1,39 @@
# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
#
# This file is part of the LibreOffice project.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
$(eval $(call gb_CustomTarget_CustomTarget,net_uretypes))
net_ure_DIR := $(gb_CustomTarget_workdir)/net_ure
net_uretypes_DIR := $(gb_CustomTarget_workdir)/net_ure/net_uretypes
$(call gb_CustomTarget_get_target,net_uretypes) : $(net_ure_DIR)/net_uretypes.done
$(net_ure_DIR)/net_uretypes.done : \
$(call gb_UnoApi_get_target,udkapi) \
$(call gb_Executable_get_target,netmaker) \
$(call gb_Executable_get_runtime_dependencies,netmaker) \
| $(net_uretypes_DIR)/.dir
$(call gb_Output_announce,$(subst $(WORKDIR)/,,$@),$(true),NET,4)
$(call gb_Trace_StartRange,$(subst $(WORKDIR)/,,$@),NET)
$(call gb_Helper_abbreviate_dirs, \
rm -r $(net_uretypes_DIR) && \
$(call gb_Helper_execute,netmaker -v -O $(net_uretypes_DIR) \
$(call gb_UnoApi_get_target,udkapi) > $@.log 2>&1 || \
(echo \
&& cat $@.log \
&& echo \
&& echo "net_uretypes failed to generate. To retry, use:" \
&& echo " make CustomTarget_net_uretypes" \
&& echo "cd into the net_ure/ directory to run make faster" \
&& echo \
&& false)) && \
touch $@)
$(call gb_Trace_EndRange,$(subst $(WORKDIR)/,,$@),NET)
# vim: set noet sw=4 ts=4:

View file

@ -0,0 +1,27 @@
# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
#
# This file is part of the LibreOffice project.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
$(eval $(call gb_DotnetLibrary_CsLibrary,net_oootypes))
$(call gb_DotnetLibrary_get_target,net_oootypes) : \
$(call gb_CustomTarget_get_target,net_oootypes)
$(eval $(call gb_DotnetLibrary_add_generated_sources,net_oootypes,\
$(gb_CustomTarget_workdir)/net_ure/net_oootypes/**/*.cs \
))
$(eval $(call gb_DotnetLibrary_link_cs_library,net_oootypes,net_uretypes))
$(eval $(call gb_DotnetLibrary_add_properties,net_oootypes,\
<AssemblyName>net_oootypes</AssemblyName> \
<Version>0.1.0</Version> \
<Company>LibreOffice</Company> \
<Description>LibreOffice datatypes for the .NET language UNO binding.</Description> \
))
# vim: set noet sw=4 ts=4:

View file

@ -0,0 +1,27 @@
# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
#
# This file is part of the LibreOffice project.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
$(eval $(call gb_DotnetLibrary_CsLibrary,net_uretypes))
$(call gb_DotnetLibrary_get_target,net_uretypes) : \
$(call gb_CustomTarget_get_target,net_uretypes)
$(eval $(call gb_DotnetLibrary_add_generated_sources,net_uretypes,\
$(gb_CustomTarget_workdir)/net_ure/net_uretypes/**/*.cs \
))
$(eval $(call gb_DotnetLibrary_link_cs_library,net_uretypes,net_basetypes))
$(eval $(call gb_DotnetLibrary_add_properties,net_uretypes,\
<AssemblyName>net_uretypes</AssemblyName> \
<Version>0.1.0</Version> \
<Company>LibreOffice</Company> \
<Description>UNO runtime datatypes for the .NET language UNO binding.</Description> \
))
# vim: set noet sw=4 ts=4:

View file

@ -10,7 +10,11 @@ $(eval $(call gb_Module_Module,net_ure))
ifeq ($(ENABLE_DOTNET),TRUE)
$(eval $(call gb_Module_add_targets,net_ure,\
CustomTarget_net_uretypes \
CustomTarget_net_oootypes \
DotnetLibrary_net_basetypes \
DotnetLibrary_net_uretypes \
DotnetLibrary_net_oootypes \
))
endif

View file

@ -2,4 +2,4 @@
Support assemblies and tools for the newer cross-platform .NET UNO binding.
Currently only contains code for the net_basetypes assembly in the source/basetypes subdirectory.
Currently only contains code for the `net_basetypes` assembly in the source/basetypes subdirectory, as well as Makefiles to build the `net_uretypes` (for `udkapi`) and `net_oootypes` (for `offapi`) assemblies, using `netmaker` from the codemaker/ module

View file

@ -33,6 +33,11 @@ $(strip $(subst ",\",$(1)))
endef
define gb_DotnetLibrary__ensure_absolute
$(if $(filter $(SRCDIR)%,$(1)),$(1),$(SRCDIR)/$(1))
endef
####### Build and Clean Targets #########
.PHONY : $(call gb_DotnetLibrary_get_clean_target,%)
@ -58,7 +63,8 @@ $(call gb_DotnetLibrary_get_target,%) :
dotnet build $$P $(DOTNET_BUILD_FLAGS) \
-o $(call gb_DotnetLibrary_get_workdir,$*) \
> $@.log 2>&1 || \
(cat $@.log \
(echo \
&& cat $@.log \
&& echo \
&& echo "A library failed to build. To retry the build, use:" \
&& echo " make DotnetLibrary_$*" \
@ -128,41 +134,63 @@ $(call gb_DotnetLibrary_get_target,$(1)) : DOTNET_ITEM_ELEMENTS += $(strip $(cal
endef
# Add one source file to the project file
# This add it to the project, and makes it a build dependency
# This adds it to the project, and makes it a build dependency
# so the library is rebuilt if the source changes
# call gb_DotnetLibrary_add_source,target,source
define gb_DotnetLibrary_add_source
$(call gb_DotnetLibrary_get_target,$(1)) : $(SRCDIR)/$(strip $(2))
$(call gb_DotnetLibrary_add_items,$(1),<Compile Include="$(SRCDIR)/$(strip $(2))"/>)
$(call gb_DotnetLibrary_get_target,$(1)) : $(call gb_DotnetLibrary__ensure_absolute,$(strip $(2)))
$(call gb_DotnetLibrary_add_items,$(1),<Compile Include="$(call gb_DotnetLibrary__ensure_absolute,$(strip $(2)))"/>)
endef
# Add source files to the project file
# This adds them to the project, and makes it them build dependency
# so the library is rebuilt if the sources change
# call gb_DotnetLibrary_add_sources,target,sources
define gb_DotnetLibrary_add_sources
$(foreach source,$(2),$(call gb_DotnetLibrary_add_source,$(1),$(source)))
endef
# Add one generated source file to the project file,
# This is not marked as makefile build dependency,
# so the library is NOT rebuilt if this source changes
# Useful for things like source globs supported by .net projects
# call gb_DotnetLibrary_add_generated_source,target,source
define gb_DotnetLibrary_add_generated_source
$(call gb_DotnetLibrary_add_items,$(1),<Compile Include="$(call gb_DotnetLibrary__ensure_absolute,$(strip $(2)))"/>)
endef
# Add generated source files to the project file,
# These are not marked as makefile build dependencies,
# so the library is NOT rebuilt if these sources change
# Useful for things like source globs supported by .net projects
# call gb_DotnetLibrary_add_generated_sources,target,sources
define gb_DotnetLibrary_add_generated_sources
$(foreach source,$(2),$(call gb_DotnetLibrary_add_generated_source,$(1),$(source)))
endef
# Link to a DotnetLibrary_CsLibrary target
# call gb_DotnetLibrary_link_cs_project,target,project
define gb_DotnetLibrary_link_cs_project
# call gb_DotnetLibrary_link_cs_library,target,library
define gb_DotnetLibrary_link_cs_library
$(call gb_DotnetLibrary_get_target,$(1)) : $(call gb_DotnetLibrary_get_target,$(strip $(2)))
$(call gb_DotnetLibrary_add_items,$(1),<ProjectReference Include="$(call gb_DotnetLibrary_get_workdir,$(strip $(2)))/$(strip $(2)).csproj"/>)
endef
# Link to a DotnetLibrary_FsLibrary target
# call gb_DotnetLibrary_link_fs_project,target,project
define gb_DotnetLibrary_link_fs_project
# call gb_DotnetLibrary_link_fs_library,target,library
define gb_DotnetLibrary_link_fs_library
$(call gb_DotnetLibrary_get_target,$(1)) : $(call gb_DotnetLibrary_get_target,$(strip $(2)))
$(call gb_DotnetLibrary_add_items,$(1),<ProjectReference Include="$(call gb_DotnetLibrary_get_workdir,$(strip $(2)))/$(strip $(2)).fsproj"/>)
endef
# Link to a DotnetLibrary_VbLibrary target
# call gb_DotnetLibrary_link_vb_project,target,project
define gb_DotnetLibrary_link_vb_project
# call gb_DotnetLibrary_link_vb_library,target,library
define gb_DotnetLibrary_link_vb_library
$(call gb_DotnetLibrary_get_target,$(1)) : $(call gb_DotnetLibrary_get_target,$(strip $(2)))
$(call gb_DotnetLibrary_add_items,$(1),<ProjectReference Include="$(call gb_DotnetLibrary_get_workdir,$(strip $(2)))/$(strip $(2)).vbproj"/>)