├── .github
└── workflows
│ └── BuildAndPublish.yml
├── .gitignore
├── LICENSE
├── NativeLibraryManager.sln
├── NativeLibraryManager
├── AssemblyAttributes.cs
├── Bitness.cs
├── Exceptions.cs
├── LibraryFile.cs
├── LibraryItem.cs
├── LibraryItemInternal.cs
├── LibraryManager.cs
├── NativeLibraryManager.csproj
├── PathHelper.cs
├── Platform.cs
└── ResourceAccessor.cs
├── Readme.md
├── TestLib
├── CMakeLists.txt
├── library.cpp
└── library.h
├── TestProcess
├── Program.cs
├── TestLib.dll
├── TestProcess.csproj
├── libTestLib.dylib
└── libTestLib.so
├── UnitTests
├── LibraryManagerTests.cs
├── TestProcess.runtimeconfig.json
└── UnitTests.csproj
└── out
├── CLAP.dll
├── Microsoft.Extensions.DependencyInjection.Abstractions.dll
├── Microsoft.Extensions.Logging.Abstractions.dll
├── Microsoft.Extensions.Logging.dll
├── Microsoft.Extensions.Options.dll
├── Microsoft.Extensions.Primitives.dll
├── NativeLibraryManager.dll
├── Newtonsoft.Json.dll
├── Serilog.Extensions.Logging.dll
├── Serilog.Sinks.Console.dll
├── Serilog.dll
├── TestProcess.deps.json
├── TestProcess.dll
└── TestProcess.runtimeconfig.json
/.github/workflows/BuildAndPublish.yml:
--------------------------------------------------------------------------------
1 | name: Build and publish Nuget
2 |
3 | on:
4 | push:
5 | tags:
6 | - '*'
7 | branches:
8 | - master
9 |
10 | jobs:
11 | test:
12 | if: ${{ !contains(github.event.head_commit.message, 'skip ci') }}
13 | runs-on: ${{ matrix.os }}
14 | strategy:
15 | matrix:
16 | os: [ubuntu-latest, macos-latest, windows-latest]
17 | steps:
18 | - uses: actions/checkout@v2
19 |
20 | - name: Setup .NET Core
21 | uses: actions/setup-dotnet@v1
22 | with:
23 | dotnet-version: 3.1.202
24 |
25 | - name: Run tests
26 | run: dotnet test
27 | build:
28 | needs: test
29 | if: ${{ startsWith(github.ref, 'refs/tags/') && !contains(github.event.head_commit.message, 'skip ci') }}
30 | runs-on: ubuntu-latest
31 | steps:
32 | - uses: actions/checkout@v2
33 | - uses: olegtarasov/get-tag@v2
34 |
35 | - name: Setup .NET Core
36 | uses: actions/setup-dotnet@v1
37 | with:
38 | dotnet-version: 3.1.202
39 |
40 | - name: Run tests
41 | run: dotnet test
42 |
43 | - name: Create the package
44 | run: dotnet pack NativeLibraryManager --configuration Release -p:PackageVersion=$GIT_TAG_NAME -o .
45 |
46 | - name: Push the package
47 | env:
48 | APIKEY: ${{ secrets.NugetKey }}
49 | run: dotnet nuget push *.nupkg -s https://api.nuget.org/v3/index.json -k $APIKEY
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # Created by https://www.gitignore.io/api/csharp,aspnetcore,visualstudio
3 | # Edit at https://www.gitignore.io/?templates=csharp,aspnetcore,visualstudio
4 |
5 | ### ASPNETCore ###
6 | ## Ignore Visual Studio temporary files, build results, and
7 | ## files generated by popular Visual Studio add-ons.
8 |
9 | # User-specific files
10 | *.suo
11 | *.user
12 | *.userosscache
13 | *.sln.docstates
14 |
15 | # User-specific files (MonoDevelop/Xamarin Studio)
16 | *.userprefs
17 |
18 | # Build results
19 | [Dd]ebug/
20 | [Dd]ebugPublic/
21 | [Rr]elease/
22 | [Rr]eleases/
23 | x64/
24 | x86/
25 | bld/
26 | [Bb]in/
27 | [Oo]bj/
28 | [Ll]og/
29 |
30 | # Visual Studio 2015 cache/options directory
31 | .vs/
32 | # Uncomment if you have tasks that create the project's static files in wwwroot
33 | #wwwroot/
34 |
35 | # MSTest test Results
36 | [Tt]est[Rr]esult*/
37 | [Bb]uild[Ll]og.*
38 |
39 | # NUNIT
40 | *.VisualState.xml
41 | TestResult.xml
42 |
43 | # Build Results of an ATL Project
44 | [Dd]ebugPS/
45 | [Rr]eleasePS/
46 | dlldata.c
47 |
48 | # DNX
49 | project.lock.json
50 | project.fragment.lock.json
51 | artifacts/
52 |
53 | *_i.c
54 | *_p.c
55 | *_i.h
56 | *.ilk
57 | *.meta
58 | *.obj
59 | *.pch
60 | *.pdb
61 | *.pgc
62 | *.pgd
63 | *.rsp
64 | *.sbr
65 | *.tlb
66 | *.tli
67 | *.tlh
68 | *.tmp
69 | *.tmp_proj
70 | *.log
71 | *.vspscc
72 | *.vssscc
73 | .builds
74 | *.pidb
75 | *.svclog
76 | *.scc
77 |
78 | # Chutzpah Test files
79 | _Chutzpah*
80 |
81 | # Visual C++ cache files
82 | ipch/
83 | *.aps
84 | *.ncb
85 | *.opendb
86 | *.opensdf
87 | *.sdf
88 | *.cachefile
89 | *.VC.db
90 | *.VC.VC.opendb
91 |
92 | # Visual Studio profiler
93 | *.psess
94 | *.vsp
95 | *.vspx
96 | *.sap
97 |
98 | # TFS 2012 Local Workspace
99 | $tf/
100 |
101 | # Guidance Automation Toolkit
102 | *.gpState
103 |
104 | # ReSharper is a .NET coding add-in
105 | _ReSharper*/
106 | *.[Rr]e[Ss]harper
107 | *.DotSettings.user
108 |
109 | # JustCode is a .NET coding add-in
110 | .JustCode
111 |
112 | # TeamCity is a build add-in
113 | _TeamCity*
114 |
115 | # DotCover is a Code Coverage Tool
116 | *.dotCover
117 |
118 | # Visual Studio code coverage results
119 | *.coverage
120 | *.coveragexml
121 |
122 | # NCrunch
123 | _NCrunch_*
124 | .*crunch*.local.xml
125 | nCrunchTemp_*
126 |
127 | # MightyMoose
128 | *.mm.*
129 | AutoTest.Net/
130 |
131 | # Web workbench (sass)
132 | .sass-cache/
133 |
134 | # Installshield output folder
135 | [Ee]xpress/
136 |
137 | # DocProject is a documentation generator add-in
138 | DocProject/buildhelp/
139 | DocProject/Help/*.HxT
140 | DocProject/Help/*.HxC
141 | DocProject/Help/*.hhc
142 | DocProject/Help/*.hhk
143 | DocProject/Help/*.hhp
144 | DocProject/Help/Html2
145 | DocProject/Help/html
146 |
147 | # Click-Once directory
148 | publish/
149 |
150 | # Publish Web Output
151 | *.[Pp]ublish.xml
152 | *.azurePubxml
153 | # TODO: Comment the next line if you want to checkin your web deploy settings
154 | # but database connection strings (with potential passwords) will be unencrypted
155 | *.pubxml
156 | *.publishproj
157 |
158 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
159 | # checkin your Azure Web App publish settings, but sensitive information contained
160 | # in these scripts will be unencrypted
161 | PublishScripts/
162 |
163 | # NuGet Packages
164 | *.nupkg
165 | # The packages folder can be ignored because of Package Restore
166 | **/packages/*
167 | # except build/, which is used as an MSBuild target.
168 | !**/packages/build/
169 | # Uncomment if necessary however generally it will be regenerated when needed
170 | #!**/packages/repositories.config
171 | # NuGet v3's project.json files produces more ignoreable files
172 | *.nuget.props
173 | *.nuget.targets
174 |
175 | # Microsoft Azure Build Output
176 | csx/
177 | *.build.csdef
178 |
179 | # Microsoft Azure Emulator
180 | ecf/
181 | rcf/
182 |
183 | # Windows Store app package directories and files
184 | AppPackages/
185 | BundleArtifacts/
186 | Package.StoreAssociation.xml
187 | _pkginfo.txt
188 |
189 | # Visual Studio cache files
190 | # files ending in .cache can be ignored
191 | *.[Cc]ache
192 | # but keep track of directories ending in .cache
193 | !*.[Cc]ache/
194 |
195 | # Others
196 | ClientBin/
197 | ~$*
198 | *~
199 | *.dbmdl
200 | *.dbproj.schemaview
201 | *.jfm
202 | *.pfx
203 | *.publishsettings
204 | node_modules/
205 | orleans.codegen.cs
206 |
207 | # Since there are multiple workflows, uncomment next line to ignore bower_components
208 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
209 | #bower_components/
210 |
211 | # RIA/Silverlight projects
212 | Generated_Code/
213 |
214 | # Backup & report files from converting an old project file
215 | # to a newer Visual Studio version. Backup files are not needed,
216 | # because we have git ;-)
217 | _UpgradeReport_Files/
218 | Backup*/
219 | UpgradeLog*.XML
220 | UpgradeLog*.htm
221 |
222 | # SQL Server files
223 | *.mdf
224 | *.ldf
225 |
226 | # Business Intelligence projects
227 | *.rdl.data
228 | *.bim.layout
229 | *.bim_*.settings
230 |
231 | # Microsoft Fakes
232 | FakesAssemblies/
233 |
234 | # GhostDoc plugin setting file
235 | *.GhostDoc.xml
236 |
237 | # Node.js Tools for Visual Studio
238 | .ntvs_analysis.dat
239 |
240 | # Visual Studio 6 build log
241 | *.plg
242 |
243 | # Visual Studio 6 workspace options file
244 | *.opt
245 |
246 | # Visual Studio LightSwitch build output
247 | **/*.HTMLClient/GeneratedArtifacts
248 | **/*.DesktopClient/GeneratedArtifacts
249 | **/*.DesktopClient/ModelManifest.xml
250 | **/*.Server/GeneratedArtifacts
251 | **/*.Server/ModelManifest.xml
252 | _Pvt_Extensions
253 |
254 | # Paket dependency manager
255 | .paket/paket.exe
256 | paket-files/
257 |
258 | # FAKE - F# Make
259 | .fake/
260 |
261 | # JetBrains Rider
262 | .idea/
263 | *.sln.iml
264 |
265 | # CodeRush
266 | .cr/
267 |
268 | # Python Tools for Visual Studio (PTVS)
269 | __pycache__/
270 | *.pyc
271 |
272 | # Cake - Uncomment if you are using it
273 | # tools/
274 |
275 | ### Csharp ###
276 | ##
277 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
278 |
279 | # User-specific files
280 | *.rsuser
281 |
282 | # User-specific files (MonoDevelop/Xamarin Studio)
283 |
284 | # Build results
285 | [Aa][Rr][Mm]/
286 | [Aa][Rr][Mm]64/
287 |
288 | # Visual Studio 2015/2017 cache/options directory
289 | # Uncomment if you have tasks that create the project's static files in wwwroot
290 |
291 | # Visual Studio 2017 auto generated files
292 | Generated\ Files/
293 |
294 | # MSTest test Results
295 |
296 | # NUNIT
297 |
298 | # Build Results of an ATL Project
299 |
300 | # Benchmark Results
301 | BenchmarkDotNet.Artifacts/
302 |
303 | # .NET Core
304 |
305 | # StyleCop
306 | StyleCopReport.xml
307 |
308 | # Files built by Visual Studio
309 | *_h.h
310 | *.iobj
311 | *.ipdb
312 | *_wpftmp.csproj
313 |
314 | # Chutzpah Test files
315 |
316 | # Visual C++ cache files
317 |
318 | # Visual Studio profiler
319 |
320 | # Visual Studio Trace Files
321 | *.e2e
322 |
323 | # TFS 2012 Local Workspace
324 |
325 | # Guidance Automation Toolkit
326 |
327 | # ReSharper is a .NET coding add-in
328 |
329 | # JustCode is a .NET coding add-in
330 |
331 | # TeamCity is a build add-in
332 |
333 | # DotCover is a Code Coverage Tool
334 |
335 | # AxoCover is a Code Coverage Tool
336 | .axoCover/*
337 | !.axoCover/settings.json
338 |
339 | # Visual Studio code coverage results
340 |
341 | # NCrunch
342 |
343 | # MightyMoose
344 |
345 | # Web workbench (sass)
346 |
347 | # Installshield output folder
348 |
349 | # DocProject is a documentation generator add-in
350 |
351 | # Click-Once directory
352 |
353 | # Publish Web Output
354 | # Note: Comment the next line if you want to checkin your web deploy settings,
355 | # but database connection strings (with potential passwords) will be unencrypted
356 |
357 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
358 | # checkin your Azure Web App publish settings, but sensitive information contained
359 | # in these scripts will be unencrypted
360 |
361 | # NuGet Packages
362 | # The packages folder can be ignored because of Package Restore
363 | **/[Pp]ackages/*
364 | # except build/, which is used as an MSBuild target.
365 | !**/[Pp]ackages/build/
366 | # Uncomment if necessary however generally it will be regenerated when needed
367 | #!**/[Pp]ackages/repositories.config
368 | # NuGet v3's project.json files produces more ignorable files
369 |
370 | # Microsoft Azure Build Output
371 |
372 | # Microsoft Azure Emulator
373 |
374 | # Windows Store app package directories and files
375 | *.appx
376 |
377 | # Visual Studio cache files
378 | # files ending in .cache can be ignored
379 | # but keep track of directories ending in .cache
380 | !?*.[Cc]ache/
381 |
382 | # Others
383 |
384 | # Including strong name files can present a security risk
385 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
386 | #*.snk
387 |
388 | # Since there are multiple workflows, uncomment next line to ignore bower_components
389 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
390 | # ASP.NET Core default setup: bower directory is configured as wwwroot/lib/ and bower restore is true
391 | **/wwwroot/lib/
392 |
393 | # RIA/Silverlight projects
394 |
395 | # Backup & report files from converting an old project file
396 | # to a newer Visual Studio version. Backup files are not needed,
397 | # because we have git ;-)
398 | ServiceFabricBackup/
399 | *.rptproj.bak
400 |
401 | # SQL Server files
402 | *.ndf
403 |
404 | # Business Intelligence projects
405 | *.rptproj.rsuser
406 | *- Backup*.rdl
407 |
408 | # Microsoft Fakes
409 |
410 | # GhostDoc plugin setting file
411 |
412 | # Node.js Tools for Visual Studio
413 |
414 | # Visual Studio 6 build log
415 |
416 | # Visual Studio 6 workspace options file
417 |
418 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
419 | *.vbw
420 |
421 | # Visual Studio LightSwitch build output
422 |
423 | # Paket dependency manager
424 |
425 | # FAKE - F# Make
426 |
427 | # JetBrains Rider
428 |
429 | # CodeRush personal settings
430 | .cr/personal
431 |
432 | # Python Tools for Visual Studio (PTVS)
433 |
434 | # Cake - Uncomment if you are using it
435 | # tools/**
436 | # !tools/packages.config
437 |
438 | # Tabs Studio
439 | *.tss
440 |
441 | # Telerik's JustMock configuration file
442 | *.jmconfig
443 |
444 | # BizTalk build output
445 | *.btp.cs
446 | *.btm.cs
447 | *.odx.cs
448 | *.xsd.cs
449 |
450 | # OpenCover UI analysis results
451 | OpenCover/
452 |
453 | # Azure Stream Analytics local run output
454 | ASALocalRun/
455 |
456 | # MSBuild Binary and Structured Log
457 | *.binlog
458 |
459 | # NVidia Nsight GPU debugger configuration file
460 | *.nvuser
461 |
462 | # MFractors (Xamarin productivity tool) working folder
463 | .mfractor/
464 |
465 | # Local History for Visual Studio
466 | .localhistory/
467 |
468 | # BeatPulse healthcheck temp database
469 | healthchecksdb
470 |
471 | ### VisualStudio ###
472 |
473 | # User-specific files
474 |
475 | # User-specific files (MonoDevelop/Xamarin Studio)
476 |
477 | # Build results
478 |
479 | # Visual Studio 2015/2017 cache/options directory
480 | # Uncomment if you have tasks that create the project's static files in wwwroot
481 |
482 | # Visual Studio 2017 auto generated files
483 |
484 | # MSTest test Results
485 |
486 | # NUNIT
487 |
488 | # Build Results of an ATL Project
489 |
490 | # Benchmark Results
491 |
492 | # .NET Core
493 |
494 | # StyleCop
495 |
496 | # Files built by Visual Studio
497 |
498 | # Chutzpah Test files
499 |
500 | # Visual C++ cache files
501 |
502 | # Visual Studio profiler
503 |
504 | # Visual Studio Trace Files
505 |
506 | # TFS 2012 Local Workspace
507 |
508 | # Guidance Automation Toolkit
509 |
510 | # ReSharper is a .NET coding add-in
511 |
512 | # JustCode is a .NET coding add-in
513 |
514 | # TeamCity is a build add-in
515 |
516 | # DotCover is a Code Coverage Tool
517 |
518 | # AxoCover is a Code Coverage Tool
519 |
520 | # Visual Studio code coverage results
521 |
522 | # NCrunch
523 |
524 | # MightyMoose
525 |
526 | # Web workbench (sass)
527 |
528 | # Installshield output folder
529 |
530 | # DocProject is a documentation generator add-in
531 |
532 | # Click-Once directory
533 |
534 | # Publish Web Output
535 | # Note: Comment the next line if you want to checkin your web deploy settings,
536 | # but database connection strings (with potential passwords) will be unencrypted
537 |
538 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
539 | # checkin your Azure Web App publish settings, but sensitive information contained
540 | # in these scripts will be unencrypted
541 |
542 | # NuGet Packages
543 | # The packages folder can be ignored because of Package Restore
544 | # except build/, which is used as an MSBuild target.
545 | # Uncomment if necessary however generally it will be regenerated when needed
546 | # NuGet v3's project.json files produces more ignorable files
547 |
548 | # Microsoft Azure Build Output
549 |
550 | # Microsoft Azure Emulator
551 |
552 | # Windows Store app package directories and files
553 |
554 | # Visual Studio cache files
555 | # files ending in .cache can be ignored
556 | # but keep track of directories ending in .cache
557 |
558 | # Others
559 |
560 | # Including strong name files can present a security risk
561 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
562 |
563 | # Since there are multiple workflows, uncomment next line to ignore bower_components
564 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
565 | # ASP.NET Core default setup: bower directory is configured as wwwroot/lib/ and bower restore is true
566 |
567 | # RIA/Silverlight projects
568 |
569 | # Backup & report files from converting an old project file
570 | # to a newer Visual Studio version. Backup files are not needed,
571 | # because we have git ;-)
572 |
573 | # SQL Server files
574 |
575 | # Business Intelligence projects
576 |
577 | # Microsoft Fakes
578 |
579 | # GhostDoc plugin setting file
580 |
581 | # Node.js Tools for Visual Studio
582 |
583 | # Visual Studio 6 build log
584 |
585 | # Visual Studio 6 workspace options file
586 |
587 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
588 |
589 | # Visual Studio LightSwitch build output
590 |
591 | # Paket dependency manager
592 |
593 | # FAKE - F# Make
594 |
595 | # JetBrains Rider
596 |
597 | # CodeRush personal settings
598 |
599 | # Python Tools for Visual Studio (PTVS)
600 |
601 | # Cake - Uncomment if you are using it
602 | # tools/**
603 | # !tools/packages.config
604 |
605 | # Tabs Studio
606 |
607 | # Telerik's JustMock configuration file
608 |
609 | # BizTalk build output
610 |
611 | # OpenCover UI analysis results
612 |
613 | # Azure Stream Analytics local run output
614 |
615 | # MSBuild Binary and Structured Log
616 |
617 | # NVidia Nsight GPU debugger configuration file
618 |
619 | # MFractors (Xamarin productivity tool) working folder
620 |
621 | # Local History for Visual Studio
622 |
623 | # BeatPulse healthcheck temp database
624 |
625 | # End of https://www.gitignore.io/api/csharp,aspnetcore,visualstudio
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Oleg Tarasov
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/NativeLibraryManager.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.28307.421
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NativeLibraryManager", "NativeLibraryManager\NativeLibraryManager.csproj", "{06FC4D35-1CD8-4AA1-ABCF-C322C16FE786}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests", "UnitTests\UnitTests.csproj", "{19BCA17B-731C-4DB4-AD59-14C315481FCE}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestProcess", "TestProcess\TestProcess.csproj", "{4D30A6BF-E6E2-4052-9FEA-F8E174E48480}"
11 | EndProject
12 | Global
13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
14 | Debug|Any CPU = Debug|Any CPU
15 | Release|Any CPU = Release|Any CPU
16 | EndGlobalSection
17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
18 | {06FC4D35-1CD8-4AA1-ABCF-C322C16FE786}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
19 | {06FC4D35-1CD8-4AA1-ABCF-C322C16FE786}.Debug|Any CPU.Build.0 = Debug|Any CPU
20 | {06FC4D35-1CD8-4AA1-ABCF-C322C16FE786}.Release|Any CPU.ActiveCfg = Release|Any CPU
21 | {06FC4D35-1CD8-4AA1-ABCF-C322C16FE786}.Release|Any CPU.Build.0 = Release|Any CPU
22 | {19BCA17B-731C-4DB4-AD59-14C315481FCE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
23 | {19BCA17B-731C-4DB4-AD59-14C315481FCE}.Debug|Any CPU.Build.0 = Debug|Any CPU
24 | {19BCA17B-731C-4DB4-AD59-14C315481FCE}.Release|Any CPU.ActiveCfg = Release|Any CPU
25 | {19BCA17B-731C-4DB4-AD59-14C315481FCE}.Release|Any CPU.Build.0 = Release|Any CPU
26 | {4D30A6BF-E6E2-4052-9FEA-F8E174E48480}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27 | {4D30A6BF-E6E2-4052-9FEA-F8E174E48480}.Debug|Any CPU.Build.0 = Debug|Any CPU
28 | {4D30A6BF-E6E2-4052-9FEA-F8E174E48480}.Release|Any CPU.ActiveCfg = Release|Any CPU
29 | {4D30A6BF-E6E2-4052-9FEA-F8E174E48480}.Release|Any CPU.Build.0 = Release|Any CPU
30 | EndGlobalSection
31 | GlobalSection(SolutionProperties) = preSolution
32 | HideSolutionNode = FALSE
33 | EndGlobalSection
34 | GlobalSection(ExtensibilityGlobals) = postSolution
35 | SolutionGuid = {5E387DB9-699C-4CD8-A939-7C87609C0405}
36 | EndGlobalSection
37 | EndGlobal
38 |
--------------------------------------------------------------------------------
/NativeLibraryManager/AssemblyAttributes.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.CompilerServices;
2 |
3 | [assembly: InternalsVisibleTo("UnitTests")]
--------------------------------------------------------------------------------
/NativeLibraryManager/Bitness.cs:
--------------------------------------------------------------------------------
1 | namespace NativeLibraryManager
2 | {
3 | ///
4 | /// Process bitness.
5 | ///
6 | public enum Bitness
7 | {
8 | ///
9 | /// 32-bit process.
10 | ///
11 | x32,
12 |
13 | ///
14 | /// 64-bit process.
15 | ///
16 | x64
17 | }
18 | }
--------------------------------------------------------------------------------
/NativeLibraryManager/Exceptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.Serialization;
3 |
4 | namespace NativeLibraryManager
5 | {
6 | ///
7 | /// Thrown when there is no binary for current platform and bitness.
8 | ///
9 | public class NoBinaryForPlatformException : Exception
10 | {
11 | ///
12 | public NoBinaryForPlatformException()
13 | {
14 | }
15 |
16 | ///
17 | protected NoBinaryForPlatformException(SerializationInfo info, StreamingContext context) : base(info, context)
18 | {
19 | }
20 |
21 | ///
22 | public NoBinaryForPlatformException(string message) : base(message)
23 | {
24 | }
25 |
26 | ///
27 | public NoBinaryForPlatformException(string message, Exception innerException) : base(message, innerException)
28 | {
29 | }
30 | }
31 |
32 | ///
33 | /// Thrown when platform is not supported.
34 | ///
35 | public class UnsupportedPlatformException : Exception
36 | {
37 | ///
38 | public UnsupportedPlatformException()
39 | {
40 | }
41 |
42 | ///
43 | protected UnsupportedPlatformException(SerializationInfo info, StreamingContext context) : base(info, context)
44 | {
45 | }
46 |
47 | ///
48 | public UnsupportedPlatformException(string message) : base(message)
49 | {
50 | }
51 |
52 | ///
53 | public UnsupportedPlatformException(string message, Exception innerException) : base(message, innerException)
54 | {
55 | }
56 | }
57 | }
--------------------------------------------------------------------------------
/NativeLibraryManager/LibraryFile.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Reflection;
4 | using System.Runtime.InteropServices;
5 | using System.Security.Cryptography;
6 | using Microsoft.Extensions.Logging;
7 |
8 | namespace NativeLibraryManager
9 | {
10 | ///
11 | /// A class to store the information about native library file.
12 | ///
13 | public class LibraryFile
14 | {
15 | ///
16 | /// Ctor.
17 | ///
18 | /// Filename to use when extracting the library.
19 | /// Library binary.
20 | public LibraryFile(string fileName, byte[] resource)
21 | {
22 | FileName = fileName;
23 | Resource = resource;
24 | }
25 |
26 | ///
27 | /// Filename to use when extracting the library.
28 | ///
29 | public string FileName { get; set; }
30 |
31 | ///
32 | /// Library binary.
33 | ///
34 | public byte[] Resource { get; set; }
35 |
36 | ///
37 | /// Specifies whether this file is a shared library, which can be loaded explicitly with
38 | /// LoadLibraryEx
on Windows and dlopen
on Linux and MacOs.
39 | ///
40 | /// Default is True
, but explicit loading is disabled by default with
41 | /// .
42 | ///
43 | /// Set this to False
if this file is not a library, but a supporting file which
44 | /// shouldn't be loaded explicitly when is True
.
45 | ///
46 | public bool CanLoadExplicitly { get; set; } = true;
47 |
48 | ///
49 | /// Gets the path to which current file will be unpacked.
50 | ///
51 | /// Target assembly for which to compute the path.
52 | [Obsolete("This method is no longer used to determine unpack path. It's determined at LibraryManager, once for all files.", true)]
53 | public string GetUnpackPath(Assembly targetAssembly)
54 | {
55 | return null;
56 | }
57 | }
58 | }
--------------------------------------------------------------------------------
/NativeLibraryManager/LibraryItem.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Reflection;
6 | using System.Runtime.InteropServices;
7 | using System.Security.Cryptography;
8 | using Microsoft.Extensions.Logging;
9 |
10 | namespace NativeLibraryManager
11 | {
12 | ///
13 | /// Library binaries for specified platform and bitness.
14 | ///
15 | public class LibraryItem
16 | {
17 | ///
18 | /// Ctor.
19 | ///
20 | /// Binary platform.
21 | /// Binary bitness.
22 | /// A collection of files for this bitness and platform.
23 | public LibraryItem(Platform platform, Bitness bitness, params LibraryFile[] files)
24 | {
25 | Platform = platform;
26 | Bitness = bitness;
27 | Files = files;
28 | }
29 |
30 | ///
31 | /// Library files.
32 | ///
33 | public LibraryFile[] Files { get; set; }
34 |
35 | ///
36 | /// Platform for which this binary is used.
37 | ///
38 | public Platform Platform { get; set; }
39 |
40 | ///
41 | /// Bitness for which this binary is used.
42 | ///
43 | public Bitness Bitness { get; set; }
44 |
45 | [Obsolete("targetAssembly is no longer required. Use the other overload.")]
46 | public void LoadItem(Assembly targetAssembly, bool loadLibrary = true)
47 | {
48 | }
49 |
50 | ///
51 | /// Unpacks the library and directly loads it if on Windows.
52 | ///
53 | /// Target directory to which library is extracted.
54 | /// Load library explicitly.
55 | public virtual void LoadItem(string targetDirectory, bool loadLibrary)
56 | {
57 | throw new InvalidOperationException("This item was never added to the LibraryManager. Create a LibraryManager, add this item and then call LibraryManager.LoadNativeLibrary().");
58 | }
59 | }
60 | }
--------------------------------------------------------------------------------
/NativeLibraryManager/LibraryItemInternal.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Runtime.InteropServices;
4 | using System.Security.Cryptography;
5 | using Microsoft.Extensions.Logging;
6 |
7 | namespace NativeLibraryManager
8 | {
9 | internal class LibraryItemInternal : LibraryItem
10 | {
11 | private readonly ILogger _logger;
12 |
13 | internal LibraryItemInternal(LibraryItem item, ILogger logger = null)
14 | : base(item.Platform, item.Bitness, item.Files)
15 | {
16 | _logger = logger;
17 | }
18 |
19 | public override void LoadItem(string targetDirectory, bool loadLibrary)
20 | {
21 | foreach (var file in Files)
22 | {
23 | string path = Path.Combine(targetDirectory, file.FileName);
24 |
25 | _logger?.LogInformation($"Unpacking native library {file.FileName} to {path}");
26 |
27 | UnpackFile(path, file.Resource);
28 |
29 | if (!loadLibrary || !file.CanLoadExplicitly)
30 | {
31 | continue;
32 | }
33 |
34 | if (Platform == Platform.Windows)
35 | {
36 | LoadWindowsLibrary(path);
37 | }
38 | else if (Platform == Platform.Linux || Platform == Platform.MacOs)
39 | {
40 | LoadNixLibrary(path);
41 | }
42 | }
43 | }
44 |
45 | private void UnpackFile(string path, byte[] bytes)
46 | {
47 | if (File.Exists(path))
48 | {
49 | _logger?.LogInformation($"File {path} already exists, computing hashes.");
50 | using (var md5 = MD5.Create())
51 | {
52 | using (var stream = File.OpenRead(path))
53 | {
54 | string fileHash = BitConverter.ToString(md5.ComputeHash(stream));
55 | string curHash = BitConverter.ToString(md5.ComputeHash(bytes));
56 |
57 | if (string.Equals(fileHash, curHash))
58 | {
59 | _logger?.LogInformation($"Hashes are equal, no need to unpack.");
60 | return;
61 | }
62 | }
63 | }
64 | }
65 |
66 | File.WriteAllBytes(path, bytes);
67 | }
68 |
69 | internal void LoadNixLibrary(string path)
70 | {
71 | _logger?.LogInformation($"Calling dlopen for {path}");
72 | var result = dlopen(path, RTLD_LAZY | RTLD_GLOBAL);
73 | _logger?.LogInformation(result == IntPtr.Zero ? "FAILED!" : "Success");
74 | }
75 |
76 | internal void LoadWindowsLibrary(string path)
77 | {
78 | _logger?.LogInformation($"Calling LoadLibraryEx for {path}...");
79 | var result = LoadLibraryEx(path, IntPtr.Zero, LoadLibraryFlags.LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LoadLibraryFlags.LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LoadLibraryFlags.LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LoadLibraryFlags.LOAD_LIBRARY_SEARCH_SYSTEM32 | LoadLibraryFlags.LOAD_LIBRARY_SEARCH_USER_DIRS);
80 | _logger?.LogInformation(result == IntPtr.Zero ? "FAILED!" : "Success");
81 | }
82 |
83 | #region dlopen
84 |
85 | private const int RTLD_LAZY = 0x00001; //Only resolve symbols as needed
86 | private const int RTLD_GLOBAL = 0x00100; //Make symbols available to libraries loaded later
87 | [DllImport("dl")]
88 | private static extern IntPtr dlopen (string file, int mode);
89 |
90 | #endregion
91 |
92 | #region LoadLibraryEx
93 |
94 | [System.Flags]
95 | private enum LoadLibraryFlags : uint
96 | {
97 | DONT_RESOLVE_DLL_REFERENCES = 0x00000001,
98 | LOAD_IGNORE_CODE_AUTHZ_LEVEL = 0x00000010,
99 | LOAD_LIBRARY_AS_DATAFILE = 0x00000002,
100 | LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE = 0x00000040,
101 | LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x00000020,
102 | LOAD_LIBRARY_SEARCH_APPLICATION_DIR = 0x00000200,
103 | LOAD_LIBRARY_SEARCH_DEFAULT_DIRS = 0x00001000,
104 | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR = 0x00000100,
105 | LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800,
106 | LOAD_LIBRARY_SEARCH_USER_DIRS = 0x00000400,
107 | LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008
108 | }
109 |
110 | [DllImport("kernel32.dll", SetLastError = true)]
111 | private static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hReservedNull, LoadLibraryFlags dwFlags);
112 |
113 | #endregion
114 | }
115 | }
--------------------------------------------------------------------------------
/NativeLibraryManager/LibraryManager.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Linq;
4 | using System.Net.Cache;
5 | using System.Reflection;
6 | using System.Runtime.InteropServices;
7 | using System.Security.Cryptography;
8 | using Microsoft.Extensions.Logging;
9 |
10 | namespace NativeLibraryManager
11 | {
12 | ///
13 | /// A class to manage, extract and load native implementations of dependent libraries.
14 | ///
15 | public class LibraryManager
16 | {
17 | private readonly object _resourceLocker = new object();
18 | private readonly LibraryItemInternal[] _items;
19 | private readonly ILogger _logger;
20 |
21 | private bool _libLoaded = false;
22 |
23 | ///
24 | /// Creates a new library manager which extracts to environment current directory by default.
25 | ///
26 | /// Calling assembly.
27 | /// Library binaries for different platforms.
28 | [Obsolete("Specifying target assembly is no longer required since default target directory is environment current directory.")]
29 | public LibraryManager(Assembly targetAssembly, params LibraryItem[] items)
30 | : this(Environment.CurrentDirectory, false, null, items)
31 | {
32 | }
33 |
34 | ///
35 | /// Creates a new library manager which extracts to environment current directory by default.
36 | ///
37 | /// Library binaries for different platforms.
38 | public LibraryManager(params LibraryItem[] items)
39 | : this(Environment.CurrentDirectory, false, null, items)
40 | {
41 | }
42 |
43 | ///
44 | /// Creates a new library manager which extracts to environment current directory by default.
45 | ///
46 | /// Logger factory.
47 | /// Library binaries for different platforms.
48 | public LibraryManager(ILoggerFactory loggerFactory, params LibraryItem[] items)
49 | : this(Environment.CurrentDirectory, false, loggerFactory, items)
50 | {
51 | }
52 |
53 | ///
54 | /// Creates a new library manager which extracts to a custom directory.
55 | ///
56 | /// IMPORTANT! Be sure this directory is discoverable by system library loader. Otherwise, your library won't be loaded.
57 | ///
58 | /// Target directory to extract the libraries.
59 | /// Logger factory.
60 | /// Library binaries for different platforms.
61 | public LibraryManager(string targetDirectory, ILoggerFactory loggerFactory, params LibraryItem[] items)
62 | : this(targetDirectory, true, loggerFactory, items)
63 | {
64 | }
65 |
66 | private LibraryManager(string targetDirectory, bool customDirectory, ILoggerFactory loggerFactory, params LibraryItem[] items)
67 | {
68 | TargetDirectory = targetDirectory;
69 | var itemLogger = loggerFactory?.CreateLogger();
70 |
71 | _logger = loggerFactory?.CreateLogger();
72 | _items = items.Select(x => new LibraryItemInternal(x, itemLogger)).ToArray();
73 |
74 | if (customDirectory)
75 | {
76 | _logger?.LogWarning("Custom directory for native libraries is specified. Be sure it is discoverable by system library loader.");
77 | }
78 | }
79 |
80 | ///
81 | /// Target directory to which native libraries will be extracted. Defaults to directory
82 | /// in which targetAssembly, passed to constructor, resides.
83 | ///
84 | public string TargetDirectory { get; }
85 |
86 | ///
87 | /// Defines whether shared libraries will be loaded explicitly. LoadLibraryEx
is
88 | /// used on Windows and dlopen
is used on Linux and MacOs to load libraries
89 | /// explicitly.
90 | ///
91 | /// WARNING! Explicit library loading on MacOs IS USELESS, and your P/Invoke call will fail unless
92 | /// library path is discoverable by system library loader.
93 | ///
94 | public bool LoadLibraryExplicit { get; set; } = false;
95 |
96 | ///
97 | /// Extract and load native library based on current platform and process bitness.
98 | /// Throws an exception if current platform is not supported.
99 | ///
100 | ///
101 | /// Use LoadLibrary API call on Windows to explicitly load library into the process.
102 | ///
103 | [Obsolete("This method is obsolete. Use LoadLibraryExplicit property.")]
104 | public void LoadNativeLibrary(bool loadLibrary)
105 | {
106 | LoadNativeLibrary();
107 | }
108 |
109 | ///
110 | /// Extract and load native library based on current platform and process bitness.
111 | /// Throws an exception if current platform is not supported.
112 | ///
113 | public void LoadNativeLibrary()
114 | {
115 | if (_libLoaded)
116 | {
117 | return;
118 | }
119 |
120 | lock (_resourceLocker)
121 | {
122 | if (_libLoaded)
123 | {
124 | return;
125 | }
126 |
127 | var item = FindItem();
128 |
129 | if (item.Platform == Platform.MacOs && LoadLibraryExplicit)
130 | {
131 | _logger?.LogWarning("Current platform is MacOs and LoadLibraryExplicit is specified. Explicit library loading on MacOs IS USELESS, and your P/Invoke call will fail unless library path is discoverable by system library loader.");
132 | }
133 |
134 | item.LoadItem(TargetDirectory, LoadLibraryExplicit);
135 |
136 | _libLoaded = true;
137 | }
138 | }
139 |
140 | ///
141 | /// Finds a library item based on current platform and bitness.
142 | ///
143 | /// Library item based on platform and bitness.
144 | ///
145 | public LibraryItem FindItem()
146 | {
147 | var platform = GetPlatform();
148 | var bitness = Environment.Is64BitProcess ? Bitness.x64 : Bitness.x32;
149 |
150 | var item = _items.FirstOrDefault(x => x.Platform == platform && x.Bitness == bitness);
151 | if (item == null)
152 | {
153 | throw new NoBinaryForPlatformException($"There is no supported native library for platform '{platform}' and bitness '{bitness}'");
154 | }
155 |
156 | return item;
157 | }
158 |
159 | ///
160 | /// Gets the platform type.
161 | ///
162 | /// Thrown when platform is not supported.
163 | public static Platform GetPlatform()
164 | {
165 | string windir = Environment.GetEnvironmentVariable("windir");
166 | if (!string.IsNullOrEmpty(windir) && windir.Contains(@"\") && Directory.Exists(windir))
167 | {
168 | return Platform.Windows;
169 | }
170 | else if (File.Exists(@"/proc/sys/kernel/ostype"))
171 | {
172 | string osType = File.ReadAllText(@"/proc/sys/kernel/ostype");
173 | if (osType.StartsWith("Linux", StringComparison.OrdinalIgnoreCase))
174 | {
175 | // Note: Android gets here too
176 | return Platform.Linux;
177 | }
178 | else
179 | {
180 | throw new UnsupportedPlatformException($"Unsupported OS: {osType}");
181 | }
182 | }
183 | else if (File.Exists(@"/System/Library/CoreServices/SystemVersion.plist"))
184 | {
185 | // Note: iOS gets here too
186 | return Platform.MacOs;
187 | }
188 | else
189 | {
190 | throw new UnsupportedPlatformException("Unsupported OS!");
191 | }
192 | }
193 | }
194 | }
--------------------------------------------------------------------------------
/NativeLibraryManager/NativeLibraryManager.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 | Oleg Tarasov
6 | A .NET Standard 2.0 library to manage native dependencies stored as binary resources.
7 | https://github.com/olegtarasov/NativeLibraryManager
8 | https://github.com/olegtarasov/NativeLibraryManager
9 |
10 |
11 |
12 | bin\Release\NativeLibraryManager.xml
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/NativeLibraryManager/PathHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Reflection;
4 |
5 | namespace NativeLibraryManager
6 | {
7 | ///
8 | /// Contains useful functions to get paths relative to target assembly.
9 | ///
10 | public static class PathHelper
11 | {
12 | ///
13 | /// Gets the directory specified assembly is located in.
14 | /// If the assembly was loaded from memory, returns environment
15 | /// working directory.
16 | ///
17 | /// Assembly to get the directory from.
18 | public static string GetCurrentDirectory(this Assembly targetAssembly)
19 | {
20 | string curDir;
21 | var ass = targetAssembly.Location;
22 | if (string.IsNullOrEmpty(ass))
23 | {
24 | curDir = Environment.CurrentDirectory;
25 | }
26 | else
27 | {
28 | curDir = Path.GetDirectoryName(ass);
29 | }
30 |
31 | return curDir;
32 | }
33 |
34 | ///
35 | /// Combines part of the path with assembly's directory.
36 | ///
37 | /// Assembly to get directory from.
38 | /// Right-hand part of the path.
39 | public static string CombineWithCurrentDirectory(this Assembly targetAssembly, string fileName)
40 | {
41 | string curDir = GetCurrentDirectory(targetAssembly);
42 | return !string.IsNullOrEmpty(curDir) ? Path.Combine(curDir, fileName) : fileName;
43 | }
44 | }
45 | }
--------------------------------------------------------------------------------
/NativeLibraryManager/Platform.cs:
--------------------------------------------------------------------------------
1 | namespace NativeLibraryManager
2 | {
3 | ///
4 | /// Platform (operating system).
5 | ///
6 | public enum Platform
7 | {
8 | ///
9 | /// Windows platform.
10 | ///
11 | Windows,
12 |
13 | ///
14 | /// Linux platform.
15 | ///
16 | Linux,
17 |
18 | ///
19 | /// MacOs platform.
20 | ///
21 | MacOs
22 | }
23 | }
--------------------------------------------------------------------------------
/NativeLibraryManager/ResourceAccessor.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Reflection;
4 |
5 | namespace NativeLibraryManager
6 | {
7 | ///
8 | /// A helper class to load resources from an assembly.
9 | ///
10 | public class ResourceAccessor
11 | {
12 | private readonly Assembly _assembly;
13 | private readonly string _assemblyName;
14 |
15 | ///
16 | /// Creates a resource accessor for the specified assembly.
17 | ///
18 | public ResourceAccessor(Assembly assembly)
19 | {
20 | _assembly = assembly;
21 | _assemblyName = _assembly.GetName().Name;
22 | }
23 |
24 | ///
25 | /// Gets a resource with specified name as an array of bytes.
26 | ///
27 | /// Resource name with folders separated by dots.
28 | ///
29 | /// When resource is not found.
30 | ///
31 | public byte[] Binary(string name)
32 | {
33 | using (var stream = new MemoryStream())
34 | {
35 | var resource = _assembly.GetManifestResourceStream(GetName(name));
36 | if (resource == null)
37 | {
38 | throw new InvalidOperationException("Resource not available.");
39 | }
40 |
41 | resource.CopyTo(stream);
42 |
43 | return stream.ToArray();
44 | }
45 | }
46 |
47 | private string GetName(string name) =>
48 | name.StartsWith(_assemblyName) ? name : $"{_assemblyName}.{name}";
49 | }
50 | }
--------------------------------------------------------------------------------
/Readme.md:
--------------------------------------------------------------------------------
1 | [](https://github.com/olegtarasov/NativeLibraryManager/actions)
2 | [](https://www.nuget.org/packages/NativeLibraryManager)
3 | [](https://www.nuget.org/packages/NativeLibraryManager)
4 |
5 | # Native dependency manager for .NET Standard libraries
6 |
7 | This library helps you manage dependencies that you want to bundle with your .NET standard assembly. Originally it was developed
8 | to be used with native shared libraries, but you can bundle any file you want.
9 |
10 | The main feature of this library is cross-platform support. You tell it which dependencies are for which platform, and `LibraryManager`
11 | will extract and load relevant files under each patform.
12 |
13 | # How to use the library
14 |
15 | ## Pack your dependencies as embedded resources
16 |
17 | Put your dependencies somewhere relative to your project. Let's assume you have one library compiled for each platform: `TestLib.dll`
18 | for Windows, `libTestLib.so` for Linux and `libTestLib.dylib` for macOs. Add these files as embedded resources to your `.csproj` as follows:
19 |
20 | ```xml
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | ```
32 |
33 | Now your dependencies will be compiled into your assembly as resources.
34 |
35 | ## Use `LibraryManager` to specify and extract dependencies
36 |
37 | ```csharp
38 | private static void Main(string[] args)
39 | {
40 | var accessor = new ResourceAccessor(Assembly.GetExecutingAssembly());
41 | var libManager = new LibraryManager(
42 | new LibraryItem(Platform.MacOs, Bitness.x64,
43 | new LibraryFile("libTestLib.dylib", accessor.Binary("libTestLib.dylib"))),
44 | new LibraryItem(Platform.Windows, Bitness.x64,
45 | new LibraryFile("TestLib.dll", accessor.Binary("TestLib.dll"))),
46 | new LibraryItem(Platform.Linux, Bitness.x64,
47 | new LibraryFile("libTestLib.so", accessor.Binary("libTestLib.so"))));
48 |
49 | libManager.LoadNativeLibrary();
50 |
51 | // Library is loaded, other code here
52 | }
53 | ```
54 |
55 | Each LibraryItem specifies a bundle of files that should be extracted for a specific platform. It this case we create 3 instances to
56 | support Windows, Linux and MacOs — all 64-bit. LibraryItem takes any number of LibraryFile objects. With these objects you specify
57 | the extracted file name and an actual binary file in the form of byte array. This is where `ResourceAccessor` comes in handy.
58 |
59 | We should note that resource name you pass to ResourceAccessor is just a path to original file relative to project root with slashes
60 | `\\` replaced with dots `.` So, for example, if we place some file in `Foo\Bar\lib.dll` project folder, we would adderss it as:
61 |
62 | ```csharp
63 | accessor.Binary("Foo.Bar.lib.dll")
64 | ```
65 |
66 | ## Target dependency directory
67 |
68 | `LibraryManager` extracts your dependencies to current process' current directory. **This is the only reliable way to use `[DllImport]` on all
69 | three platforms.**
70 |
71 | If your current directory isn't writable, you are generally out of luck. You can use an overload of `LibraryManager`'s constructor which accepts
72 | a custom target directory, but then you need to do one of the following:
73 |
74 | 1. Ensure that target directory that you specify is discoverable by system library loader. The safest bet is to ensure it's on your `PATH`
75 | **before the whole process starts**.
76 | 2. Enable explicit library loading with `LibraryManager.LoadLibraryExplicit` (read the next section for details).
77 | **This will not work on MacOs.** If your target path is not discoverable by system library loader, `dlopen` will succeed on MacOs, but your
78 | P/Invoke calls will fail. This problem can be mitigated by manually resolving function pointers, but this approach is not yet implemented
79 | in this library.
80 |
81 | ## Explicit library loading
82 |
83 | **Warning! Explicit library loading on MacOs IS USELESS, and your P/Invoke call will fail unless library path is discoverable by system library
84 | loader (by adding target path to `LD_LIBRARY_PATH` or `PATH` before running your app, for example).**
85 |
86 | In previous versions of `NativeLibraryManager` the default behavior was to explicitly load every file using `LoadLibraryEx` on Windows
87 | and `dlopen` on Linux (explit loading wasn't implemented for MacOs). This approach was quite rigid and caused at least two problems:
88 |
89 | 1. There might have been some supporting files which didn't require explicit loading. You couldn't load some files and not load the others.
90 | 2. You should have observed a specific order in which you defined `LibraryFile`s if some of them were dependent on others.
91 |
92 | Starting from v. `1.0.21` explicit loading is disabled by default.
93 |
94 | Nevertheless, sometimes you might want to load libraries explicitly. To do so, set `LibraryManager.LoadLibraryExplicit` to `True` before
95 | calling `LibraryManager.LoadNativeLibrary()`.
96 |
97 | You can also set `LibraryFile.CanLoadExplicitly` to `False` for supporting files, which you want to exclude from explicit loading.
98 |
99 | When `LibraryManager.LoadLibraryExplicit` is `True`, `LoadLibraryEx` will be called to explicitly load libraries on Windows, and
100 | `dlopen` will be called on Linux and MacOs.
101 |
102 | ### Dependency load order with explicit loading
103 |
104 | As mentioned earlier, there is a restriction when explicitly loading dependencies. If your native library depends on other native
105 | libraries, which you would also like to bundle with you assembly, you should observe a special order in which you specify `LibraryFile` items.
106 | You should put libraries with no dependencies ("leaves") first, and dependent libraries last. Use `ldd` on Linux or `Dependency Walker` on
107 | Windows to discover the dependecies in your libraries.
108 |
109 | ## Logging with `Microsoft.Extensions.Logging`
110 |
111 | `LibraryManager` writes a certain amount of logs in case you would like to debug something. This library uses .NET Core
112 | `Microsoft.Extensions.Logging` abstraction, so in order to enable logging, just obtain an instance of
113 | `Microsoft.Extensions.Logging.ILoggerFactory` and pass it as a parameter to `LibraryManager` constructor.
--------------------------------------------------------------------------------
/TestLib/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.14)
2 | project(TestLib)
3 |
4 | set(CMAKE_CXX_STANDARD 17)
5 |
6 | add_compile_definitions(DLL_EXPORTS)
7 |
8 | add_library(TestLib SHARED library.cpp library.h)
--------------------------------------------------------------------------------
/TestLib/library.cpp:
--------------------------------------------------------------------------------
1 | #include "library.h"
2 |
3 | #include
4 |
5 | #if defined(_WIN32)
6 | #define OS "Windows"
7 | #elif defined(__linux__)
8 | #define OS "Linux"
9 | #elif defined(__APPLE__)
10 | #define OS "MacOS"
11 | #else
12 | #define OS "Unknown OS"
13 | #endif
14 |
15 | int hello() {
16 | return 42;
17 | }
--------------------------------------------------------------------------------
/TestLib/library.h:
--------------------------------------------------------------------------------
1 | #ifndef TESTLIB_LIBRARY_H
2 | #define TESTLIB_LIBRARY_H
3 |
4 | #if defined DLL_EXPORTS
5 | #if defined WIN32
6 | #define LIB_API(RetType) extern "C" __declspec(dllexport) RetType
7 | #else
8 | #define LIB_API(RetType) extern "C" RetType __attribute__((visibility("default")))
9 | #endif
10 | #else
11 | #if defined WIN32
12 | #define LIB_API(RetType) extern "C" __declspec(dllimport) RetType
13 | #else
14 | #define LIB_API(RetType) extern "C" RetType
15 | #endif
16 | #endif
17 |
18 | LIB_API(int) hello();
19 |
20 | #endif //TESTLIB_LIBRARY_H
--------------------------------------------------------------------------------
/TestProcess/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Reflection;
4 | using System.Runtime.CompilerServices;
5 | using System.Runtime.InteropServices;
6 | using CLAP;
7 | using Microsoft.Extensions.Logging;
8 | using NativeLibraryManager;
9 | using Serilog;
10 | using Serilog.Extensions.Logging;
11 |
12 | namespace TestProcess
13 | {
14 | internal class Program
15 | {
16 | internal static int Main(string[] args)
17 | {
18 | Log.Logger = new LoggerConfiguration()
19 | .MinimumLevel.Debug()
20 | .WriteTo.Console()
21 | .CreateLogger();
22 | var factory = new LoggerFactory(new[] {new SerilogLoggerProvider() });
23 |
24 | try
25 | {
26 | return Parser.Run(args, new UnitTests(factory));
27 | }
28 | catch (Exception e)
29 | {
30 | Log.ForContext().Error($"Test failed with exception: {e.GetType().Name}, {e.Message}");
31 | return 1;
32 | }
33 | }
34 | }
35 |
36 | internal class UnitTests
37 | {
38 | [DllImport("TestLib")]
39 | private static extern int hello();
40 |
41 | private readonly ILoggerFactory _factory;
42 | private readonly ILogger _logger;
43 |
44 | public UnitTests(ILoggerFactory factory)
45 | {
46 | _factory = factory;
47 | _logger = factory.CreateLogger();
48 | try
49 | {
50 | File.Delete("libTestLib.dylib");
51 | File.Delete("libTestLib.so");
52 | File.Delete("TestLib.dll");
53 | }
54 | catch (Exception e)
55 | {
56 | _logger.LogWarning(e, $"Failed to cleanup libraries before running a test: {e.Message}");
57 | }
58 | }
59 |
60 | [Verb]
61 | public int CanLoadLibraryFromCurrentDirAndCallFunction()
62 | {
63 | var accessor = new ResourceAccessor(Assembly.GetExecutingAssembly());
64 | var libManager = new LibraryManager(
65 | _factory,
66 | new LibraryItem(Platform.MacOs, Bitness.x64,
67 | new LibraryFile("libTestLib.dylib", accessor.Binary("libTestLib.dylib"))),
68 | new LibraryItem(Platform.Windows, Bitness.x64,
69 | new LibraryFile("TestLib.dll", accessor.Binary("TestLib.dll"))),
70 | new LibraryItem(Platform.Linux, Bitness.x64,
71 | new LibraryFile("libTestLib.so", accessor.Binary("libTestLib.so"))));
72 |
73 | libManager.LoadNativeLibrary();
74 |
75 | int result = hello();
76 |
77 | _logger.LogInformation($"Function result is {result}");
78 |
79 | return result == 42 ? 0 : 1;
80 | }
81 |
82 | [Verb]
83 | public int CanLoadLibraryFromTempDirAndCallFunction()
84 | {
85 | string tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N"));
86 | Directory.CreateDirectory(tempDir);
87 |
88 | var accessor = new ResourceAccessor(Assembly.GetExecutingAssembly());
89 | var libManager = new LibraryManager(
90 | tempDir,
91 | _factory,
92 | new LibraryItem(Platform.MacOs, Bitness.x64,
93 | new LibraryFile("libTestLib.dylib", accessor.Binary("libTestLib.dylib"))),
94 | new LibraryItem(Platform.Windows, Bitness.x64,
95 | new LibraryFile("TestLib.dll", accessor.Binary("TestLib.dll"))),
96 | new LibraryItem(Platform.Linux, Bitness.x64,
97 | new LibraryFile("libTestLib.so", accessor.Binary("libTestLib.so"))))
98 | {
99 | LoadLibraryExplicit = true
100 | };
101 |
102 | var item = libManager.FindItem();
103 | libManager.LoadNativeLibrary();
104 |
105 | int result;
106 | try
107 | {
108 | result = hello();
109 | }
110 | catch (DllNotFoundException)
111 | {
112 | if (item.Platform == Platform.MacOs)
113 | {
114 | _logger.LogWarning("Hit an expected exception on MacOs. Skipping test.");
115 | return 0;
116 | }
117 |
118 | throw;
119 | }
120 |
121 | _logger.LogInformation($"Function result is {result}");
122 |
123 | return result == 42 ? 0 : 1;
124 | }
125 | }
126 | }
--------------------------------------------------------------------------------
/TestProcess/TestLib.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/olegtarasov/NativeLibraryManager/af85f6e13d351bc386ff8be06d186a59f9eba0bf/TestProcess/TestLib.dll
--------------------------------------------------------------------------------
/TestProcess/TestProcess.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | netcoreapp3.1
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/TestProcess/libTestLib.dylib:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/olegtarasov/NativeLibraryManager/af85f6e13d351bc386ff8be06d186a59f9eba0bf/TestProcess/libTestLib.dylib
--------------------------------------------------------------------------------
/TestProcess/libTestLib.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/olegtarasov/NativeLibraryManager/af85f6e13d351bc386ff8be06d186a59f9eba0bf/TestProcess/libTestLib.so
--------------------------------------------------------------------------------
/UnitTests/LibraryManagerTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.IO;
4 | using System.Reflection;
5 | using System.Runtime.InteropServices;
6 | using MartinCostello.Logging.XUnit;
7 | using Microsoft.Extensions.Logging;
8 | using NativeLibraryManager;
9 | using Shouldly;
10 | using Xunit;
11 | using Xunit.Abstractions;
12 |
13 | namespace UnitTests
14 | {
15 | ///
16 | /// We need to use a separate process per test so that we get a clear picture (libraries must be unloaded before the next test).
17 | ///
18 | public class LibraryManagerTests
19 | {
20 | private readonly ITestOutputHelper _outputHelper;
21 |
22 | public LibraryManagerTests(ITestOutputHelper outputHelper)
23 | {
24 | _outputHelper = outputHelper;
25 | }
26 |
27 | [Fact]
28 | public void CanLoadLibraryFromCurrentDirAndCallFunction()
29 | {
30 | RunTest(nameof(CanLoadLibraryFromCurrentDirAndCallFunction)).ShouldBe(0);
31 | }
32 |
33 | [Fact]
34 | public void CanLoadLibraryFromTempDirAndCallFunction()
35 | {
36 | RunTest(nameof(CanLoadLibraryFromTempDirAndCallFunction)).ShouldBe(0);
37 | }
38 |
39 | [Fact]
40 | public void CanCreateManagerWithoutLogging()
41 | {
42 | var manager = new LibraryManager();
43 | }
44 |
45 | private int RunTest(string name)
46 | {
47 | var process = Process.Start(new ProcessStartInfo("dotnet", $"TestProcess.dll {name}")
48 | {
49 | UseShellExecute = false,
50 | RedirectStandardOutput = true,
51 | RedirectStandardError = true,
52 | });
53 |
54 | process.OutputDataReceived += ProcessOnOutputDataReceived;
55 | process.ErrorDataReceived += ProcessOnOutputDataReceived;
56 | process.BeginOutputReadLine();
57 | process.BeginErrorReadLine();
58 |
59 | process.WaitForExit();
60 | process.CancelOutputRead();
61 | process.CancelErrorRead();
62 |
63 | return process.ExitCode;
64 | }
65 |
66 | private void ProcessOnOutputDataReceived (object sender, DataReceivedEventArgs e)
67 | {
68 | if (!string.IsNullOrEmpty(e?.Data))
69 | {
70 | _outputHelper.WriteLine(e.Data);
71 | }
72 | }
73 | }
74 | }
--------------------------------------------------------------------------------
/UnitTests/TestProcess.runtimeconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "runtimeOptions": {
3 | "tfm": "netcoreapp3.1",
4 | "framework": {
5 | "name": "Microsoft.NETCore.App",
6 | "version": "3.1.0"
7 | }
8 | }
9 | }
--------------------------------------------------------------------------------
/UnitTests/UnitTests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 |
6 | false
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | PreserveNewest
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/out/CLAP.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/olegtarasov/NativeLibraryManager/af85f6e13d351bc386ff8be06d186a59f9eba0bf/out/CLAP.dll
--------------------------------------------------------------------------------
/out/Microsoft.Extensions.DependencyInjection.Abstractions.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/olegtarasov/NativeLibraryManager/af85f6e13d351bc386ff8be06d186a59f9eba0bf/out/Microsoft.Extensions.DependencyInjection.Abstractions.dll
--------------------------------------------------------------------------------
/out/Microsoft.Extensions.Logging.Abstractions.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/olegtarasov/NativeLibraryManager/af85f6e13d351bc386ff8be06d186a59f9eba0bf/out/Microsoft.Extensions.Logging.Abstractions.dll
--------------------------------------------------------------------------------
/out/Microsoft.Extensions.Logging.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/olegtarasov/NativeLibraryManager/af85f6e13d351bc386ff8be06d186a59f9eba0bf/out/Microsoft.Extensions.Logging.dll
--------------------------------------------------------------------------------
/out/Microsoft.Extensions.Options.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/olegtarasov/NativeLibraryManager/af85f6e13d351bc386ff8be06d186a59f9eba0bf/out/Microsoft.Extensions.Options.dll
--------------------------------------------------------------------------------
/out/Microsoft.Extensions.Primitives.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/olegtarasov/NativeLibraryManager/af85f6e13d351bc386ff8be06d186a59f9eba0bf/out/Microsoft.Extensions.Primitives.dll
--------------------------------------------------------------------------------
/out/NativeLibraryManager.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/olegtarasov/NativeLibraryManager/af85f6e13d351bc386ff8be06d186a59f9eba0bf/out/NativeLibraryManager.dll
--------------------------------------------------------------------------------
/out/Newtonsoft.Json.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/olegtarasov/NativeLibraryManager/af85f6e13d351bc386ff8be06d186a59f9eba0bf/out/Newtonsoft.Json.dll
--------------------------------------------------------------------------------
/out/Serilog.Extensions.Logging.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/olegtarasov/NativeLibraryManager/af85f6e13d351bc386ff8be06d186a59f9eba0bf/out/Serilog.Extensions.Logging.dll
--------------------------------------------------------------------------------
/out/Serilog.Sinks.Console.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/olegtarasov/NativeLibraryManager/af85f6e13d351bc386ff8be06d186a59f9eba0bf/out/Serilog.Sinks.Console.dll
--------------------------------------------------------------------------------
/out/Serilog.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/olegtarasov/NativeLibraryManager/af85f6e13d351bc386ff8be06d186a59f9eba0bf/out/Serilog.dll
--------------------------------------------------------------------------------
/out/TestProcess.deps.json:
--------------------------------------------------------------------------------
1 | {
2 | "runtimeTarget": {
3 | "name": ".NETCoreApp,Version=v3.1",
4 | "signature": ""
5 | },
6 | "compilationOptions": {},
7 | "targets": {
8 | ".NETCoreApp,Version=v3.1": {
9 | "TestProcess/1.0.0": {
10 | "dependencies": {
11 | "CLAP-DotNetCore": "4.6.1",
12 | "NativeLibraryManager": "1.0.0",
13 | "Serilog.Extensions.Logging": "3.0.1",
14 | "Serilog.Sinks.Console": "3.1.1"
15 | },
16 | "runtime": {
17 | "TestProcess.dll": {}
18 | }
19 | },
20 | "CLAP-DotNetCore/4.6.1": {
21 | "dependencies": {
22 | "Newtonsoft.Json": "12.0.3"
23 | },
24 | "runtime": {
25 | "lib/netstandard2.0/CLAP.dll": {
26 | "assemblyVersion": "4.2.0.0",
27 | "fileVersion": "4.2.0.0"
28 | }
29 | }
30 | },
31 | "Microsoft.Extensions.DependencyInjection.Abstractions/2.0.0": {
32 | "runtime": {
33 | "lib/netstandard2.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll": {
34 | "assemblyVersion": "2.0.0.0",
35 | "fileVersion": "2.0.0.17205"
36 | }
37 | }
38 | },
39 | "Microsoft.Extensions.Logging/2.0.0": {
40 | "dependencies": {
41 | "Microsoft.Extensions.DependencyInjection.Abstractions": "2.0.0",
42 | "Microsoft.Extensions.Logging.Abstractions": "3.1.4",
43 | "Microsoft.Extensions.Options": "2.0.0"
44 | },
45 | "runtime": {
46 | "lib/netstandard2.0/Microsoft.Extensions.Logging.dll": {
47 | "assemblyVersion": "2.0.0.0",
48 | "fileVersion": "2.0.0.17205"
49 | }
50 | }
51 | },
52 | "Microsoft.Extensions.Logging.Abstractions/3.1.4": {
53 | "runtime": {
54 | "lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.dll": {
55 | "assemblyVersion": "3.1.4.0",
56 | "fileVersion": "3.100.420.21409"
57 | }
58 | }
59 | },
60 | "Microsoft.Extensions.Options/2.0.0": {
61 | "dependencies": {
62 | "Microsoft.Extensions.DependencyInjection.Abstractions": "2.0.0",
63 | "Microsoft.Extensions.Primitives": "2.0.0"
64 | },
65 | "runtime": {
66 | "lib/netstandard2.0/Microsoft.Extensions.Options.dll": {
67 | "assemblyVersion": "2.0.0.0",
68 | "fileVersion": "2.0.0.17205"
69 | }
70 | }
71 | },
72 | "Microsoft.Extensions.Primitives/2.0.0": {
73 | "dependencies": {
74 | "System.Runtime.CompilerServices.Unsafe": "4.4.0"
75 | },
76 | "runtime": {
77 | "lib/netstandard2.0/Microsoft.Extensions.Primitives.dll": {
78 | "assemblyVersion": "2.0.0.0",
79 | "fileVersion": "2.0.0.17205"
80 | }
81 | }
82 | },
83 | "Microsoft.NETCore.Platforms/1.1.0": {},
84 | "Microsoft.NETCore.Targets/1.1.0": {},
85 | "Newtonsoft.Json/12.0.3": {
86 | "runtime": {
87 | "lib/netstandard2.0/Newtonsoft.Json.dll": {
88 | "assemblyVersion": "12.0.0.0",
89 | "fileVersion": "12.0.3.23909"
90 | }
91 | }
92 | },
93 | "runtime.native.System/4.3.0": {
94 | "dependencies": {
95 | "Microsoft.NETCore.Platforms": "1.1.0",
96 | "Microsoft.NETCore.Targets": "1.1.0"
97 | }
98 | },
99 | "Serilog/2.8.0": {
100 | "dependencies": {
101 | "System.Collections.NonGeneric": "4.3.0"
102 | },
103 | "runtime": {
104 | "lib/netstandard2.0/Serilog.dll": {
105 | "assemblyVersion": "2.0.0.0",
106 | "fileVersion": "2.8.0.0"
107 | }
108 | }
109 | },
110 | "Serilog.Extensions.Logging/3.0.1": {
111 | "dependencies": {
112 | "Microsoft.Extensions.Logging": "2.0.0",
113 | "Serilog": "2.8.0"
114 | },
115 | "runtime": {
116 | "lib/netstandard2.0/Serilog.Extensions.Logging.dll": {
117 | "assemblyVersion": "2.0.0.0",
118 | "fileVersion": "3.0.1.0"
119 | }
120 | }
121 | },
122 | "Serilog.Sinks.Console/3.1.1": {
123 | "dependencies": {
124 | "Serilog": "2.8.0",
125 | "System.Console": "4.3.0",
126 | "System.Runtime.InteropServices": "4.3.0",
127 | "System.Runtime.InteropServices.RuntimeInformation": "4.3.0"
128 | },
129 | "runtime": {
130 | "lib/netcoreapp1.1/Serilog.Sinks.Console.dll": {
131 | "assemblyVersion": "3.1.1.0",
132 | "fileVersion": "3.1.1.0"
133 | }
134 | }
135 | },
136 | "System.Collections.NonGeneric/4.3.0": {
137 | "dependencies": {
138 | "System.Diagnostics.Debug": "4.3.0",
139 | "System.Globalization": "4.3.0",
140 | "System.Resources.ResourceManager": "4.3.0",
141 | "System.Runtime": "4.3.0",
142 | "System.Runtime.Extensions": "4.3.0",
143 | "System.Threading": "4.3.0"
144 | }
145 | },
146 | "System.Console/4.3.0": {
147 | "dependencies": {
148 | "Microsoft.NETCore.Platforms": "1.1.0",
149 | "Microsoft.NETCore.Targets": "1.1.0",
150 | "System.IO": "4.3.0",
151 | "System.Runtime": "4.3.0",
152 | "System.Text.Encoding": "4.3.0"
153 | }
154 | },
155 | "System.Diagnostics.Debug/4.3.0": {
156 | "dependencies": {
157 | "Microsoft.NETCore.Platforms": "1.1.0",
158 | "Microsoft.NETCore.Targets": "1.1.0",
159 | "System.Runtime": "4.3.0"
160 | }
161 | },
162 | "System.Globalization/4.3.0": {
163 | "dependencies": {
164 | "Microsoft.NETCore.Platforms": "1.1.0",
165 | "Microsoft.NETCore.Targets": "1.1.0",
166 | "System.Runtime": "4.3.0"
167 | }
168 | },
169 | "System.IO/4.3.0": {
170 | "dependencies": {
171 | "Microsoft.NETCore.Platforms": "1.1.0",
172 | "Microsoft.NETCore.Targets": "1.1.0",
173 | "System.Runtime": "4.3.0",
174 | "System.Text.Encoding": "4.3.0",
175 | "System.Threading.Tasks": "4.3.0"
176 | }
177 | },
178 | "System.Reflection/4.3.0": {
179 | "dependencies": {
180 | "Microsoft.NETCore.Platforms": "1.1.0",
181 | "Microsoft.NETCore.Targets": "1.1.0",
182 | "System.IO": "4.3.0",
183 | "System.Reflection.Primitives": "4.3.0",
184 | "System.Runtime": "4.3.0"
185 | }
186 | },
187 | "System.Reflection.Extensions/4.3.0": {
188 | "dependencies": {
189 | "Microsoft.NETCore.Platforms": "1.1.0",
190 | "Microsoft.NETCore.Targets": "1.1.0",
191 | "System.Reflection": "4.3.0",
192 | "System.Runtime": "4.3.0"
193 | }
194 | },
195 | "System.Reflection.Primitives/4.3.0": {
196 | "dependencies": {
197 | "Microsoft.NETCore.Platforms": "1.1.0",
198 | "Microsoft.NETCore.Targets": "1.1.0",
199 | "System.Runtime": "4.3.0"
200 | }
201 | },
202 | "System.Resources.ResourceManager/4.3.0": {
203 | "dependencies": {
204 | "Microsoft.NETCore.Platforms": "1.1.0",
205 | "Microsoft.NETCore.Targets": "1.1.0",
206 | "System.Globalization": "4.3.0",
207 | "System.Reflection": "4.3.0",
208 | "System.Runtime": "4.3.0"
209 | }
210 | },
211 | "System.Runtime/4.3.0": {
212 | "dependencies": {
213 | "Microsoft.NETCore.Platforms": "1.1.0",
214 | "Microsoft.NETCore.Targets": "1.1.0"
215 | }
216 | },
217 | "System.Runtime.CompilerServices.Unsafe/4.4.0": {},
218 | "System.Runtime.Extensions/4.3.0": {
219 | "dependencies": {
220 | "Microsoft.NETCore.Platforms": "1.1.0",
221 | "Microsoft.NETCore.Targets": "1.1.0",
222 | "System.Runtime": "4.3.0"
223 | }
224 | },
225 | "System.Runtime.Handles/4.3.0": {
226 | "dependencies": {
227 | "Microsoft.NETCore.Platforms": "1.1.0",
228 | "Microsoft.NETCore.Targets": "1.1.0",
229 | "System.Runtime": "4.3.0"
230 | }
231 | },
232 | "System.Runtime.InteropServices/4.3.0": {
233 | "dependencies": {
234 | "Microsoft.NETCore.Platforms": "1.1.0",
235 | "Microsoft.NETCore.Targets": "1.1.0",
236 | "System.Reflection": "4.3.0",
237 | "System.Reflection.Primitives": "4.3.0",
238 | "System.Runtime": "4.3.0",
239 | "System.Runtime.Handles": "4.3.0"
240 | }
241 | },
242 | "System.Runtime.InteropServices.RuntimeInformation/4.3.0": {
243 | "dependencies": {
244 | "System.Reflection": "4.3.0",
245 | "System.Reflection.Extensions": "4.3.0",
246 | "System.Resources.ResourceManager": "4.3.0",
247 | "System.Runtime": "4.3.0",
248 | "System.Runtime.InteropServices": "4.3.0",
249 | "System.Threading": "4.3.0",
250 | "runtime.native.System": "4.3.0"
251 | }
252 | },
253 | "System.Text.Encoding/4.3.0": {
254 | "dependencies": {
255 | "Microsoft.NETCore.Platforms": "1.1.0",
256 | "Microsoft.NETCore.Targets": "1.1.0",
257 | "System.Runtime": "4.3.0"
258 | }
259 | },
260 | "System.Threading/4.3.0": {
261 | "dependencies": {
262 | "System.Runtime": "4.3.0",
263 | "System.Threading.Tasks": "4.3.0"
264 | }
265 | },
266 | "System.Threading.Tasks/4.3.0": {
267 | "dependencies": {
268 | "Microsoft.NETCore.Platforms": "1.1.0",
269 | "Microsoft.NETCore.Targets": "1.1.0",
270 | "System.Runtime": "4.3.0"
271 | }
272 | },
273 | "NativeLibraryManager/1.0.0": {
274 | "dependencies": {
275 | "Microsoft.Extensions.Logging.Abstractions": "3.1.4"
276 | },
277 | "runtime": {
278 | "NativeLibraryManager.dll": {}
279 | }
280 | }
281 | }
282 | },
283 | "libraries": {
284 | "TestProcess/1.0.0": {
285 | "type": "project",
286 | "serviceable": false,
287 | "sha512": ""
288 | },
289 | "CLAP-DotNetCore/4.6.1": {
290 | "type": "package",
291 | "serviceable": true,
292 | "sha512": "sha512-YsclUrS/6en17MqAOrGSHIFnTmFClnARAyRi96FYkAoioS/qFLcivgzY7vwRN5nIbuo/Y2CqzzDsOVKNjKkQZQ==",
293 | "path": "clap-dotnetcore/4.6.1",
294 | "hashPath": "clap-dotnetcore.4.6.1.nupkg.sha512"
295 | },
296 | "Microsoft.Extensions.DependencyInjection.Abstractions/2.0.0": {
297 | "type": "package",
298 | "serviceable": true,
299 | "sha512": "sha512-eUdJ0Q/GfVyUJc0Jal5L1QZLceL78pvEM9wEKcHeI24KorqMDoVX+gWsMGLulQMfOwsUaPtkpQM2pFERTzSfSg==",
300 | "path": "microsoft.extensions.dependencyinjection.abstractions/2.0.0",
301 | "hashPath": "microsoft.extensions.dependencyinjection.abstractions.2.0.0.nupkg.sha512"
302 | },
303 | "Microsoft.Extensions.Logging/2.0.0": {
304 | "type": "package",
305 | "serviceable": true,
306 | "sha512": "sha512-VP10syWV/vxYYMKgZ2eDESmUsz3gPxvBn5J6tkVN8lI4M+dF43RN8fWsEPbcAneDmZrHl3Pv23z05nmyGkJlpg==",
307 | "path": "microsoft.extensions.logging/2.0.0",
308 | "hashPath": "microsoft.extensions.logging.2.0.0.nupkg.sha512"
309 | },
310 | "Microsoft.Extensions.Logging.Abstractions/3.1.4": {
311 | "type": "package",
312 | "serviceable": true,
313 | "sha512": "sha512-JNPxhw2XwhjfGFyIkA5eBfzUDPNpa6Q50HJ2F6lCAMoSa1GquAktTrl4PhEyTYFNmu09B0E90WhYsUb3kmSkOA==",
314 | "path": "microsoft.extensions.logging.abstractions/3.1.4",
315 | "hashPath": "microsoft.extensions.logging.abstractions.3.1.4.nupkg.sha512"
316 | },
317 | "Microsoft.Extensions.Options/2.0.0": {
318 | "type": "package",
319 | "serviceable": true,
320 | "sha512": "sha512-sAKBgjl2gWsECBLLR9K54T7/uZaP2n9GhMYHay/oOLfvpvX0+iNAlQ2NJgVE352C9Fs5CDV3VbNTK8T2aNKQFA==",
321 | "path": "microsoft.extensions.options/2.0.0",
322 | "hashPath": "microsoft.extensions.options.2.0.0.nupkg.sha512"
323 | },
324 | "Microsoft.Extensions.Primitives/2.0.0": {
325 | "type": "package",
326 | "serviceable": true,
327 | "sha512": "sha512-ukg53qNlqTrK38WA30b5qhw0GD7y3jdI9PHHASjdKyTcBHTevFM2o23tyk3pWCgAV27Bbkm+CPQ2zUe1ZOuYSA==",
328 | "path": "microsoft.extensions.primitives/2.0.0",
329 | "hashPath": "microsoft.extensions.primitives.2.0.0.nupkg.sha512"
330 | },
331 | "Microsoft.NETCore.Platforms/1.1.0": {
332 | "type": "package",
333 | "serviceable": true,
334 | "sha512": "sha512-kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A==",
335 | "path": "microsoft.netcore.platforms/1.1.0",
336 | "hashPath": "microsoft.netcore.platforms.1.1.0.nupkg.sha512"
337 | },
338 | "Microsoft.NETCore.Targets/1.1.0": {
339 | "type": "package",
340 | "serviceable": true,
341 | "sha512": "sha512-aOZA3BWfz9RXjpzt0sRJJMjAscAUm3Hoa4UWAfceV9UTYxgwZ1lZt5nO2myFf+/jetYQo4uTP7zS8sJY67BBxg==",
342 | "path": "microsoft.netcore.targets/1.1.0",
343 | "hashPath": "microsoft.netcore.targets.1.1.0.nupkg.sha512"
344 | },
345 | "Newtonsoft.Json/12.0.3": {
346 | "type": "package",
347 | "serviceable": true,
348 | "sha512": "sha512-6mgjfnRB4jKMlzHSl+VD+oUc1IebOZabkbyWj2RiTgWwYPPuaK1H97G1sHqGwPlS5npiF5Q0OrxN1wni2n5QWg==",
349 | "path": "newtonsoft.json/12.0.3",
350 | "hashPath": "newtonsoft.json.12.0.3.nupkg.sha512"
351 | },
352 | "runtime.native.System/4.3.0": {
353 | "type": "package",
354 | "serviceable": true,
355 | "sha512": "sha512-c/qWt2LieNZIj1jGnVNsE2Kl23Ya2aSTBuXMD6V7k9KWr6l16Tqdwq+hJScEpWER9753NWC8h96PaVNY5Ld7Jw==",
356 | "path": "runtime.native.system/4.3.0",
357 | "hashPath": "runtime.native.system.4.3.0.nupkg.sha512"
358 | },
359 | "Serilog/2.8.0": {
360 | "type": "package",
361 | "serviceable": true,
362 | "sha512": "sha512-zjuKXW5IQws43IHX7VY9nURsaCiBYh2kyJCWLJRSWrTsx/syBKHV8MibWe2A+QH3Er0AiwA+OJmO3DhFJDY1+A==",
363 | "path": "serilog/2.8.0",
364 | "hashPath": "serilog.2.8.0.nupkg.sha512"
365 | },
366 | "Serilog.Extensions.Logging/3.0.1": {
367 | "type": "package",
368 | "serviceable": true,
369 | "sha512": "sha512-U0xbGoZuxJRjE3C5vlCfrf9a4xHTmbrCXKmaA14cHAqiT1Qir0rkV7Xss9GpPJR3MRYH19DFUUqZ9hvWeJrzdQ==",
370 | "path": "serilog.extensions.logging/3.0.1",
371 | "hashPath": "serilog.extensions.logging.3.0.1.nupkg.sha512"
372 | },
373 | "Serilog.Sinks.Console/3.1.1": {
374 | "type": "package",
375 | "serviceable": true,
376 | "sha512": "sha512-56mI5AqvyF/i/c2451nvV71kq370XOCE4Uu5qiaJ295sOhMb9q3BWwG7mWLOVSnmpWiq0SBT3SXfgRXGNP6vzA==",
377 | "path": "serilog.sinks.console/3.1.1",
378 | "hashPath": "serilog.sinks.console.3.1.1.nupkg.sha512"
379 | },
380 | "System.Collections.NonGeneric/4.3.0": {
381 | "type": "package",
382 | "serviceable": true,
383 | "sha512": "sha512-prtjIEMhGUnQq6RnPEYLpFt8AtLbp9yq2zxOSrY7KJJZrw25Fi97IzBqY7iqssbM61Ek5b8f3MG/sG1N2sN5KA==",
384 | "path": "system.collections.nongeneric/4.3.0",
385 | "hashPath": "system.collections.nongeneric.4.3.0.nupkg.sha512"
386 | },
387 | "System.Console/4.3.0": {
388 | "type": "package",
389 | "serviceable": true,
390 | "sha512": "sha512-DHDrIxiqk1h03m6khKWV2X8p/uvN79rgSqpilL6uzpmSfxfU5ng8VcPtW4qsDsQDHiTv6IPV9TmD5M/vElPNLg==",
391 | "path": "system.console/4.3.0",
392 | "hashPath": "system.console.4.3.0.nupkg.sha512"
393 | },
394 | "System.Diagnostics.Debug/4.3.0": {
395 | "type": "package",
396 | "serviceable": true,
397 | "sha512": "sha512-ZUhUOdqmaG5Jk3Xdb8xi5kIyQYAA4PnTNlHx1mu9ZY3qv4ELIdKbnL/akbGaKi2RnNUWaZsAs31rvzFdewTj2g==",
398 | "path": "system.diagnostics.debug/4.3.0",
399 | "hashPath": "system.diagnostics.debug.4.3.0.nupkg.sha512"
400 | },
401 | "System.Globalization/4.3.0": {
402 | "type": "package",
403 | "serviceable": true,
404 | "sha512": "sha512-kYdVd2f2PAdFGblzFswE4hkNANJBKRmsfa2X5LG2AcWE1c7/4t0pYae1L8vfZ5xvE2nK/R9JprtToA61OSHWIg==",
405 | "path": "system.globalization/4.3.0",
406 | "hashPath": "system.globalization.4.3.0.nupkg.sha512"
407 | },
408 | "System.IO/4.3.0": {
409 | "type": "package",
410 | "serviceable": true,
411 | "sha512": "sha512-3qjaHvxQPDpSOYICjUoTsmoq5u6QJAFRUITgeT/4gqkF1bajbSmb1kwSxEA8AHlofqgcKJcM8udgieRNhaJ5Cg==",
412 | "path": "system.io/4.3.0",
413 | "hashPath": "system.io.4.3.0.nupkg.sha512"
414 | },
415 | "System.Reflection/4.3.0": {
416 | "type": "package",
417 | "serviceable": true,
418 | "sha512": "sha512-KMiAFoW7MfJGa9nDFNcfu+FpEdiHpWgTcS2HdMpDvt9saK3y/G4GwprPyzqjFH9NTaGPQeWNHU+iDlDILj96aQ==",
419 | "path": "system.reflection/4.3.0",
420 | "hashPath": "system.reflection.4.3.0.nupkg.sha512"
421 | },
422 | "System.Reflection.Extensions/4.3.0": {
423 | "type": "package",
424 | "serviceable": true,
425 | "sha512": "sha512-rJkrJD3kBI5B712aRu4DpSIiHRtr6QlfZSQsb0hYHrDCZORXCFjQfoipo2LaMUHoT9i1B7j7MnfaEKWDFmFQNQ==",
426 | "path": "system.reflection.extensions/4.3.0",
427 | "hashPath": "system.reflection.extensions.4.3.0.nupkg.sha512"
428 | },
429 | "System.Reflection.Primitives/4.3.0": {
430 | "type": "package",
431 | "serviceable": true,
432 | "sha512": "sha512-5RXItQz5As4xN2/YUDxdpsEkMhvw3e6aNveFXUn4Hl/udNTCNhnKp8lT9fnc3MhvGKh1baak5CovpuQUXHAlIA==",
433 | "path": "system.reflection.primitives/4.3.0",
434 | "hashPath": "system.reflection.primitives.4.3.0.nupkg.sha512"
435 | },
436 | "System.Resources.ResourceManager/4.3.0": {
437 | "type": "package",
438 | "serviceable": true,
439 | "sha512": "sha512-/zrcPkkWdZmI4F92gL/TPumP98AVDu/Wxr3CSJGQQ+XN6wbRZcyfSKVoPo17ilb3iOr0cCRqJInGwNMolqhS8A==",
440 | "path": "system.resources.resourcemanager/4.3.0",
441 | "hashPath": "system.resources.resourcemanager.4.3.0.nupkg.sha512"
442 | },
443 | "System.Runtime/4.3.0": {
444 | "type": "package",
445 | "serviceable": true,
446 | "sha512": "sha512-JufQi0vPQ0xGnAczR13AUFglDyVYt4Kqnz1AZaiKZ5+GICq0/1MH/mO/eAJHt/mHW1zjKBJd7kV26SrxddAhiw==",
447 | "path": "system.runtime/4.3.0",
448 | "hashPath": "system.runtime.4.3.0.nupkg.sha512"
449 | },
450 | "System.Runtime.CompilerServices.Unsafe/4.4.0": {
451 | "type": "package",
452 | "serviceable": true,
453 | "sha512": "sha512-9dLLuBxr5GNmOfl2jSMcsHuteEg32BEfUotmmUkmZjpR3RpVHE8YQwt0ow3p6prwA1ME8WqDVZqrr8z6H8G+Kw==",
454 | "path": "system.runtime.compilerservices.unsafe/4.4.0",
455 | "hashPath": "system.runtime.compilerservices.unsafe.4.4.0.nupkg.sha512"
456 | },
457 | "System.Runtime.Extensions/4.3.0": {
458 | "type": "package",
459 | "serviceable": true,
460 | "sha512": "sha512-guW0uK0fn5fcJJ1tJVXYd7/1h5F+pea1r7FLSOz/f8vPEqbR2ZAknuRDvTQ8PzAilDveOxNjSfr0CHfIQfFk8g==",
461 | "path": "system.runtime.extensions/4.3.0",
462 | "hashPath": "system.runtime.extensions.4.3.0.nupkg.sha512"
463 | },
464 | "System.Runtime.Handles/4.3.0": {
465 | "type": "package",
466 | "serviceable": true,
467 | "sha512": "sha512-OKiSUN7DmTWeYb3l51A7EYaeNMnvxwE249YtZz7yooT4gOZhmTjIn48KgSsw2k2lYdLgTKNJw/ZIfSElwDRVgg==",
468 | "path": "system.runtime.handles/4.3.0",
469 | "hashPath": "system.runtime.handles.4.3.0.nupkg.sha512"
470 | },
471 | "System.Runtime.InteropServices/4.3.0": {
472 | "type": "package",
473 | "serviceable": true,
474 | "sha512": "sha512-uv1ynXqiMK8mp1GM3jDqPCFN66eJ5w5XNomaK2XD+TuCroNTLFGeZ+WCmBMcBDyTFKou3P6cR6J/QsaqDp7fGQ==",
475 | "path": "system.runtime.interopservices/4.3.0",
476 | "hashPath": "system.runtime.interopservices.4.3.0.nupkg.sha512"
477 | },
478 | "System.Runtime.InteropServices.RuntimeInformation/4.3.0": {
479 | "type": "package",
480 | "serviceable": true,
481 | "sha512": "sha512-cbz4YJMqRDR7oLeMRbdYv7mYzc++17lNhScCX0goO2XpGWdvAt60CGN+FHdePUEHCe/Jy9jUlvNAiNdM+7jsOw==",
482 | "path": "system.runtime.interopservices.runtimeinformation/4.3.0",
483 | "hashPath": "system.runtime.interopservices.runtimeinformation.4.3.0.nupkg.sha512"
484 | },
485 | "System.Text.Encoding/4.3.0": {
486 | "type": "package",
487 | "serviceable": true,
488 | "sha512": "sha512-BiIg+KWaSDOITze6jGQynxg64naAPtqGHBwDrLaCtixsa5bKiR8dpPOHA7ge3C0JJQizJE+sfkz1wV+BAKAYZw==",
489 | "path": "system.text.encoding/4.3.0",
490 | "hashPath": "system.text.encoding.4.3.0.nupkg.sha512"
491 | },
492 | "System.Threading/4.3.0": {
493 | "type": "package",
494 | "serviceable": true,
495 | "sha512": "sha512-VkUS0kOBcUf3Wwm0TSbrevDDZ6BlM+b/HRiapRFWjM5O0NS0LviG0glKmFK+hhPDd1XFeSdU1GmlLhb2CoVpIw==",
496 | "path": "system.threading/4.3.0",
497 | "hashPath": "system.threading.4.3.0.nupkg.sha512"
498 | },
499 | "System.Threading.Tasks/4.3.0": {
500 | "type": "package",
501 | "serviceable": true,
502 | "sha512": "sha512-LbSxKEdOUhVe8BezB/9uOGGppt+nZf6e1VFyw6v3DN6lqitm0OSn2uXMOdtP0M3W4iMcqcivm2J6UgqiwwnXiA==",
503 | "path": "system.threading.tasks/4.3.0",
504 | "hashPath": "system.threading.tasks.4.3.0.nupkg.sha512"
505 | },
506 | "NativeLibraryManager/1.0.0": {
507 | "type": "project",
508 | "serviceable": false,
509 | "sha512": ""
510 | }
511 | }
512 | }
--------------------------------------------------------------------------------
/out/TestProcess.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/olegtarasov/NativeLibraryManager/af85f6e13d351bc386ff8be06d186a59f9eba0bf/out/TestProcess.dll
--------------------------------------------------------------------------------
/out/TestProcess.runtimeconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "runtimeOptions": {
3 | "tfm": "netcoreapp3.1",
4 | "framework": {
5 | "name": "Microsoft.NETCore.App",
6 | "version": "3.1.0"
7 | }
8 | }
9 | }
--------------------------------------------------------------------------------