working on c and cmake plugins
This commit is contained in:
parent
7ea6ca3d65
commit
d616184a2e
27 changed files with 1543 additions and 1 deletions
201
gradle-plugin-c/LICENSE.txt
Normal file
201
gradle-plugin-c/LICENSE.txt
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright {yyyy} {name of copyright owner}
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
8
gradle-plugin-c/NOTICE.txt
Normal file
8
gradle-plugin-c/NOTICE.txt
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
|
||||||
|
This work is derived from
|
||||||
|
|
||||||
|
https://github.com/jjohannes/plain-c
|
||||||
|
|
||||||
|
as of January 14, 2024
|
||||||
|
|
||||||
|
(Apache License 2.0)
|
81
gradle-plugin-c/README.md
Normal file
81
gradle-plugin-c/README.md
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
# C - Gradle plugin
|
||||||
|
|
||||||
|
An experimental plugin for customized **C** development with Gradle.
|
||||||
|
It showcases how to use tasks that are provided by Gradle core for **C** development,
|
||||||
|
such as `org.gradle.language.c.tasks.CCompile`, directly as part of a custom build system.
|
||||||
|
This can make sense in a highly customized Gradle build system where specific (and multiple) **C** compilation/assembling/linking
|
||||||
|
steps are part of a larger build pipeline with other custom Gradle tasks.
|
||||||
|
|
||||||
|
The plugin provides an extension called `c` to:
|
||||||
|
|
||||||
|
- Set the `targetPlatform` property of a task to a generic platform via `targetPlatform.set(c.platform())`
|
||||||
|
- Set the `toolChain` property of a task to a locally installed tool via `toolChain.set(c.localTool("version", "/path/to/tool", ".o"))`
|
||||||
|
- Set the `toolChain` property of a task to a tool located in a ZIP file in a Maven repository via `toolChain.set(c.repositoryTool("group", "name", "version", "path/in/zip", ".o"))`
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
```
|
||||||
|
plugins {
|
||||||
|
id 'org.xbib.gradle.plugin.c"
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.register<CCompile>("compileC") {
|
||||||
|
toolChain.set(c.localTool("14.0.0", "/usr/bin/clang", ".o"))
|
||||||
|
targetPlatform.set(c.platform())
|
||||||
|
|
||||||
|
source(layout.projectDirectory.files("src/c").asFileTree)
|
||||||
|
includes(layout.projectDirectory.files("src/headers"))
|
||||||
|
compilerArgs.add("-S")
|
||||||
|
|
||||||
|
objectFileDir.set(layout.buildDirectory.dir("out/o"))
|
||||||
|
}
|
||||||
|
|
||||||
|
val compileC2 = tasks.register<CCompile>("compileC2") {
|
||||||
|
toolChain.set(c.repositoryTool("com.example", "vendor-x", "1.2", "bin/xcc", ".src"))
|
||||||
|
targetPlatform.set(c.platform())
|
||||||
|
|
||||||
|
source(layout.projectDirectory.files("src/c-special").asFileTree)
|
||||||
|
includes(layout.projectDirectory.files("src/headers"))
|
||||||
|
|
||||||
|
objectFileDir.set(layout.buildDirectory.dir("out/src"))
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.register<Assemble>("assembleC2") {
|
||||||
|
toolChain.set(c.repositoryTool("com.example", "vendor-x", "1.2", "bin/xas", ".o"))
|
||||||
|
targetPlatform.set(c.platform())
|
||||||
|
|
||||||
|
source(compileC2.map { it.objectFileDir.asFileTree })
|
||||||
|
includes(layout.projectDirectory.files("src/headers"))
|
||||||
|
assemblerArgs = listOf("-D")
|
||||||
|
|
||||||
|
objectFileDir = layout.buildDirectory.dir("out/o2").get().asFile
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## How does this work?
|
||||||
|
|
||||||
|
In order to fully configure one of the native tasks of Gradle (such as `org.gradle.language.c.tasks.CCompile`),
|
||||||
|
you require a **NativeToolchain** (instance of `org.gradle.nativeplatform.toolchain.NativeToolChain`)
|
||||||
|
and a **TargetPlatform** (instance of `org.gradle.nativeplatform.platform.NativePlatform`).
|
||||||
|
Gradle's own [native languages plugins](https://docs.gradle.org/current/userguide/plugin_reference.html#native_languages)
|
||||||
|
pre-configure these task properties through the so-called _native toolchain registry_.
|
||||||
|
This allows, for example, to compile the same code for multiple target platforms with different tools in the same build.
|
||||||
|
This is great, if this is what you need. However, in a scenario where we do not care about this feature and would rather register
|
||||||
|
tasks directly, we miss flexibility as the _native toolchain registry_ in Gradle is not very flexible right now and makes it difficult or impossible to register
|
||||||
|
your own tools (and it has not been improved for several years).
|
||||||
|
|
||||||
|
The [CExtension.java](src/main/java/org/xbib/gradle/plugin/c/CExtension.java) class now allows you to
|
||||||
|
set the `targetPlatform` and `toolChain` properties of any task without the _native toolchain registry_.
|
||||||
|
It does so by utilising internal Gradle APIs to:
|
||||||
|
- Construct a generic `NativePlatform` object. This is the same everywhere and will be ignored during tool selection.
|
||||||
|
In our scenario, we do not care about different platforms.
|
||||||
|
- Construct a `NativeToolChain` instance based on a concrete executable. Either by providing a concrete path to
|
||||||
|
an executable (`localTool(...)`) or coordinates pointing at a ZIP file in a Maven repository (`repositoryTool(...)`).
|
||||||
|
In the latter case, Gradle's dependency management is used to find, download, extract and cache the tool.
|
||||||
|
|
||||||
|
Behind the custom `NativeToolChain` implementation is a custom `PlatformToolProvider` implementation and extensions of
|
||||||
|
Gradle's `NativeCompiler` implementations. This allows for more customization and extension of Gradle's functionality
|
||||||
|
in this area. This uses a lot of APIs from `internal` packages. Which, however, have not been touched for years.
|
||||||
|
|
||||||
|
This showcase could help to determine which APIs in this area should probably be public.
|
||||||
|
|
30
gradle-plugin-c/build.gradle
Normal file
30
gradle-plugin-c/build.gradle
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
plugins {
|
||||||
|
alias(libs.plugins.publish)
|
||||||
|
}
|
||||||
|
|
||||||
|
apply plugin: 'com.gradle.plugin-publish'
|
||||||
|
|
||||||
|
apply from: rootProject.file('gradle/compile/groovy.gradle')
|
||||||
|
apply from: rootProject.file('gradle/test/junit5.gradle')
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
api gradleApi()
|
||||||
|
testImplementation gradleTestKit()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (project.hasProperty('gradle.publish.key')) {
|
||||||
|
gradlePlugin {
|
||||||
|
website = 'https://xbib.org/joerg/gradle-plugins/src/branch/main/gradle-plugin-c'
|
||||||
|
vcsUrl = 'https://xbib.org/joerg/gradle-plugins'
|
||||||
|
plugins {
|
||||||
|
cPlugin {
|
||||||
|
id = 'org.xbib.gradle.plugin.c'
|
||||||
|
implementationClass = 'org.xbib.gradle.plugin.c.CPlugin'
|
||||||
|
version = project.version
|
||||||
|
description = 'Gradle plugin for build with C'
|
||||||
|
displayName = 'Gradle Plugin for build with C'
|
||||||
|
tags.set(['c'])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
2
gradle-plugin-c/gradle.properties
Normal file
2
gradle-plugin-c/gradle.properties
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
name = gradle-plugin-c
|
||||||
|
version = 3.1.0
|
|
@ -0,0 +1,59 @@
|
||||||
|
package org.xbib.gradle.plugin.c;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import org.gradle.api.artifacts.Configuration;
|
||||||
|
import org.gradle.api.artifacts.ConfigurationContainer;
|
||||||
|
import org.gradle.api.artifacts.dsl.DependencyHandler;
|
||||||
|
import org.gradle.api.attributes.Attribute;
|
||||||
|
import org.gradle.api.file.FileCollection;
|
||||||
|
import org.gradle.api.model.ObjectFactory;
|
||||||
|
import org.gradle.nativeplatform.platform.NativePlatform;
|
||||||
|
import org.gradle.nativeplatform.platform.internal.DefaultArchitecture;
|
||||||
|
import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform;
|
||||||
|
import org.gradle.nativeplatform.platform.internal.DefaultOperatingSystem;
|
||||||
|
import org.gradle.nativeplatform.toolchain.NativeToolChain;
|
||||||
|
import org.xbib.gradle.plugin.c.toolchain.CNativeToolChain;
|
||||||
|
|
||||||
|
public abstract class CExtension {
|
||||||
|
|
||||||
|
static final Attribute<Boolean> EXTRACTED_TOOLS_ATTRIBUTE = Attribute.of("extracted-tools", Boolean.class);
|
||||||
|
|
||||||
|
static final NativePlatform GENERIC_NATIVE_PLATFORM = new DefaultNativePlatform(
|
||||||
|
"generic_platform",
|
||||||
|
new DefaultOperatingSystem("generic_os"),
|
||||||
|
new DefaultArchitecture("generic_arch")
|
||||||
|
);
|
||||||
|
|
||||||
|
public NativeToolChain localTool(String version, String location, String objectFileExtension) {
|
||||||
|
File tool = new File(location);
|
||||||
|
return getObjects().newInstance(CNativeToolChain.class, version, tool.getName(),
|
||||||
|
getObjects().fileCollection().from(tool), objectFileExtension);
|
||||||
|
}
|
||||||
|
|
||||||
|
public NativeToolChain repositoryTool(String group,
|
||||||
|
String name,
|
||||||
|
String version,
|
||||||
|
String locationInZip,
|
||||||
|
String objectFileExtension) {
|
||||||
|
Configuration toolConfiguration = getConfigurations().detachedConfiguration(
|
||||||
|
getDependencies().create(group + ":" + name + ":" + version + "@zip"));
|
||||||
|
FileCollection tool = toolConfiguration.getIncoming().artifactView(a ->
|
||||||
|
a.getAttributes().attribute(EXTRACTED_TOOLS_ATTRIBUTE, true))
|
||||||
|
.getFiles().getAsFileTree().filter(file -> file.getPath().endsWith(locationInZip));
|
||||||
|
return getObjects().newInstance(CNativeToolChain.class, name, version, tool, objectFileExtension);
|
||||||
|
}
|
||||||
|
|
||||||
|
public NativePlatform platform() {
|
||||||
|
return GENERIC_NATIVE_PLATFORM;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
abstract protected ObjectFactory getObjects();
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
abstract protected ConfigurationContainer getConfigurations();
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
abstract protected DependencyHandler getDependencies();
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
package org.xbib.gradle.plugin.c;
|
||||||
|
|
||||||
|
import org.gradle.api.Plugin;
|
||||||
|
import org.gradle.api.Project;
|
||||||
|
import org.xbib.gradle.plugin.c.toolchain.transform.ExtractZipTransform;
|
||||||
|
import static org.gradle.api.artifacts.type.ArtifactTypeDefinition.ARTIFACT_TYPE_ATTRIBUTE;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
abstract public class CPlugin implements Plugin<Project> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void apply(final Project project) {
|
||||||
|
// Register extension
|
||||||
|
project.getExtensions().create("c", CExtension.class);
|
||||||
|
// Make the ExtractZipTransform known
|
||||||
|
project.getDependencies().getAttributesSchema().attribute(CExtension.EXTRACTED_TOOLS_ATTRIBUTE);
|
||||||
|
project.getDependencies().getArtifactTypes().maybeCreate("zip")
|
||||||
|
.getAttributes().attribute(CExtension.EXTRACTED_TOOLS_ATTRIBUTE, false);
|
||||||
|
project.getDependencies().registerTransform(ExtractZipTransform.class, t -> {
|
||||||
|
t.getFrom().attribute(CExtension.EXTRACTED_TOOLS_ATTRIBUTE, false).attribute(ARTIFACT_TYPE_ATTRIBUTE, "zip");
|
||||||
|
t.getTo().attribute(CExtension.EXTRACTED_TOOLS_ATTRIBUTE, true).attribute(ARTIFACT_TYPE_ATTRIBUTE, "zip");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
package org.xbib.gradle.plugin.c.tasks;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import org.gradle.api.provider.MapProperty;
|
||||||
|
import org.gradle.api.tasks.CacheableTask;
|
||||||
|
import org.gradle.api.tasks.Input;
|
||||||
|
import org.gradle.language.c.tasks.CCompile;
|
||||||
|
import org.gradle.nativeplatform.toolchain.internal.NativeCompileSpec;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extension of the 'org.gradle.language.c.tasks.CCompile' that supports defining different compiler arguments
|
||||||
|
* for different source files.
|
||||||
|
*/
|
||||||
|
@CacheableTask
|
||||||
|
public abstract class ExtendedCCompile extends CCompile {
|
||||||
|
|
||||||
|
@Input
|
||||||
|
public abstract MapProperty<String, List<String>> getPerFileCompilerArgs();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected NativeCompileSpec createCompileSpec() {
|
||||||
|
return new ExtendedCCompileSpec();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configureSpec(NativeCompileSpec spec) {
|
||||||
|
super.configureSpec(spec);
|
||||||
|
ExtendedCCompileSpec extendedCCompileSpec = (ExtendedCCompileSpec) spec;
|
||||||
|
extendedCCompileSpec.getPerFileCompilerArgs().putAll(getPerFileCompilerArgs().get());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
package org.xbib.gradle.plugin.c.tasks;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import org.gradle.language.c.internal.DefaultCCompileSpec;
|
||||||
|
|
||||||
|
public class ExtendedCCompileSpec extends DefaultCCompileSpec {
|
||||||
|
|
||||||
|
private final Map<String, List<String>> perFileCompilerArgs = new HashMap<>();
|
||||||
|
|
||||||
|
public Map<String, List<String>> getPerFileCompilerArgs() {
|
||||||
|
return perFileCompilerArgs;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,80 @@
|
||||||
|
package org.xbib.gradle.plugin.c.tasks;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import org.gradle.api.file.ConfigurableFileCollection;
|
||||||
|
import org.gradle.api.tasks.CacheableTask;
|
||||||
|
import org.gradle.api.tasks.TaskAction;
|
||||||
|
import org.gradle.api.tasks.WorkResult;
|
||||||
|
import org.gradle.internal.operations.logging.BuildOperationLogger;
|
||||||
|
import org.gradle.language.assembler.internal.DefaultAssembleSpec;
|
||||||
|
import org.gradle.language.assembler.tasks.Assemble;
|
||||||
|
import org.gradle.language.base.internal.compile.Compiler;
|
||||||
|
import org.gradle.language.base.internal.tasks.StaleOutputCleaner;
|
||||||
|
import org.gradle.nativeplatform.internal.BuildOperationLoggingCompilerDecorator;
|
||||||
|
import org.gradle.nativeplatform.platform.internal.NativePlatformInternal;
|
||||||
|
import org.gradle.nativeplatform.toolchain.internal.NativeToolChainInternal;
|
||||||
|
import org.gradle.nativeplatform.toolchain.internal.compilespec.AssembleSpec;
|
||||||
|
import org.gradle.work.ChangeType;
|
||||||
|
import org.gradle.work.FileChange;
|
||||||
|
import org.gradle.work.Incremental;
|
||||||
|
import org.gradle.work.InputChanges;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Incremental and cacheable version of the 'org.gradle.language.assembler.tasks.Assemble' task.
|
||||||
|
*/
|
||||||
|
@CacheableTask
|
||||||
|
public abstract class IncrementalAssemble extends Assemble {
|
||||||
|
|
||||||
|
@Incremental
|
||||||
|
@Override
|
||||||
|
public ConfigurableFileCollection getSource() {
|
||||||
|
return super.getSource();
|
||||||
|
}
|
||||||
|
|
||||||
|
@TaskAction
|
||||||
|
public void assemble(InputChanges inputs) {
|
||||||
|
// Copied from super class and adjusted for incremental assembling
|
||||||
|
|
||||||
|
BuildOperationLogger operationLogger = getOperationLoggerFactory().newOperationLogger(getName(), getTemporaryDir());
|
||||||
|
|
||||||
|
List<File> toDelete = new ArrayList<>();
|
||||||
|
List<File> toAssemble = new ArrayList<>();
|
||||||
|
|
||||||
|
for (FileChange change : inputs.getFileChanges(super.getSource())) {
|
||||||
|
if (change.getChangeType() == ChangeType.REMOVED) {
|
||||||
|
toDelete.add(change.getFile());
|
||||||
|
}
|
||||||
|
if (change.getChangeType() != ChangeType.REMOVED) {
|
||||||
|
toAssemble.add(change.getFile());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean cleanedOutputs = StaleOutputCleaner.cleanOutputs(
|
||||||
|
getDeleter(),
|
||||||
|
toDelete,
|
||||||
|
getObjectFileDir()
|
||||||
|
);
|
||||||
|
|
||||||
|
DefaultAssembleSpec spec = new DefaultAssembleSpec();
|
||||||
|
spec.setTempDir(getTemporaryDir());
|
||||||
|
|
||||||
|
spec.setObjectFileDir(getObjectFileDir());
|
||||||
|
spec.source(toAssemble);
|
||||||
|
spec.include(getIncludes());
|
||||||
|
spec.args(getAssemblerArgs());
|
||||||
|
spec.setOperationLogger(operationLogger);
|
||||||
|
|
||||||
|
NativeToolChainInternal nativeToolChain = (NativeToolChainInternal) getToolChain().get();
|
||||||
|
NativePlatformInternal nativePlatform = (NativePlatformInternal) getTargetPlatform().get();
|
||||||
|
Compiler<AssembleSpec> compiler = nativeToolChain.select(nativePlatform).newCompiler(AssembleSpec.class);
|
||||||
|
WorkResult result = BuildOperationLoggingCompilerDecorator.wrap(compiler).execute(spec);
|
||||||
|
setDidWork(result.getDidWork() || cleanedOutputs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void assemble() {
|
||||||
|
// disable assemble() without 'inputs' argument
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
package org.xbib.gradle.plugin.c.toolchain;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import org.gradle.api.NonNullApi;
|
||||||
|
import org.gradle.api.file.FileCollection;
|
||||||
|
import org.gradle.api.model.ObjectFactory;
|
||||||
|
import org.gradle.nativeplatform.platform.internal.NativePlatformInternal;
|
||||||
|
import org.gradle.nativeplatform.toolchain.NativeToolChain;
|
||||||
|
import org.gradle.nativeplatform.toolchain.internal.NativeLanguage;
|
||||||
|
import org.gradle.nativeplatform.toolchain.internal.NativeToolChainInternal;
|
||||||
|
import org.gradle.nativeplatform.toolchain.internal.PlatformToolProvider;
|
||||||
|
|
||||||
|
@NonNullApi
|
||||||
|
public abstract class CNativeToolChain implements NativeToolChain, NativeToolChainInternal {
|
||||||
|
|
||||||
|
private final String toolName;
|
||||||
|
|
||||||
|
private final String toolVersion;
|
||||||
|
|
||||||
|
private final FileCollection tool;
|
||||||
|
|
||||||
|
private final String objectFileExtension;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public CNativeToolChain(String toolName,
|
||||||
|
String toolVersion,
|
||||||
|
FileCollection tool,
|
||||||
|
String objectFileExtension) {
|
||||||
|
this.toolName = toolName;
|
||||||
|
this.toolVersion = toolVersion;
|
||||||
|
this.tool = tool;
|
||||||
|
this.objectFileExtension = objectFileExtension;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return toolName + "_" + toolVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PlatformToolProvider select(NativePlatformInternal nativePlatform) {
|
||||||
|
return getObjects().newInstance(CPlatformToolProvider.class, tool, toolVersion, objectFileExtension);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PlatformToolProvider select(NativeLanguage nativeLanguage, NativePlatformInternal nativePlatform) {
|
||||||
|
return select(nativePlatform);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDisplayName() {
|
||||||
|
return getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getOutputType() {
|
||||||
|
return getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void assertSupported() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
abstract protected ObjectFactory getObjects();
|
||||||
|
}
|
|
@ -0,0 +1,202 @@
|
||||||
|
package org.xbib.gradle.plugin.c.toolchain;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import org.gradle.api.file.FileCollection;
|
||||||
|
import org.gradle.internal.logging.text.DiagnosticsVisitor;
|
||||||
|
import org.gradle.internal.operations.BuildOperationExecutor;
|
||||||
|
import org.gradle.internal.work.WorkerLeaseService;
|
||||||
|
import org.gradle.language.base.internal.compile.CompileSpec;
|
||||||
|
import org.gradle.language.base.internal.compile.Compiler;
|
||||||
|
import org.gradle.language.base.internal.compile.DefaultCompilerVersion;
|
||||||
|
import org.gradle.language.base.internal.compile.VersionAwareCompiler;
|
||||||
|
import org.gradle.nativeplatform.internal.CompilerOutputFileNamingSchemeFactory;
|
||||||
|
import org.gradle.nativeplatform.internal.LinkerSpec;
|
||||||
|
import org.gradle.nativeplatform.internal.StaticLibraryArchiverSpec;
|
||||||
|
import org.gradle.nativeplatform.toolchain.internal.CommandLineToolContext;
|
||||||
|
import org.gradle.nativeplatform.toolchain.internal.CommandLineToolInvocationWorker;
|
||||||
|
import org.gradle.nativeplatform.toolchain.internal.DefaultCommandLineToolInvocationWorker;
|
||||||
|
import org.gradle.nativeplatform.toolchain.internal.DefaultMutableCommandLineToolContext;
|
||||||
|
import org.gradle.nativeplatform.toolchain.internal.EmptySystemLibraries;
|
||||||
|
import org.gradle.nativeplatform.toolchain.internal.OutputCleaningCompiler;
|
||||||
|
import org.gradle.nativeplatform.toolchain.internal.PlatformToolProvider;
|
||||||
|
import org.gradle.nativeplatform.toolchain.internal.SystemLibraries;
|
||||||
|
import org.gradle.nativeplatform.toolchain.internal.ToolType;
|
||||||
|
import org.gradle.nativeplatform.toolchain.internal.compilespec.AssembleSpec;
|
||||||
|
import org.gradle.nativeplatform.toolchain.internal.compilespec.CCompileSpec;
|
||||||
|
import org.gradle.nativeplatform.toolchain.internal.metadata.CompilerMetadata;
|
||||||
|
import org.gradle.nativeplatform.toolchain.internal.tools.CommandLineToolSearchResult;
|
||||||
|
import org.gradle.process.internal.ExecActionFactory;
|
||||||
|
import org.gradle.util.internal.VersionNumber;
|
||||||
|
import org.xbib.gradle.plugin.c.toolchain.tools.Assembler;
|
||||||
|
import org.xbib.gradle.plugin.c.toolchain.tools.CCompiler;
|
||||||
|
import org.xbib.gradle.plugin.c.toolchain.tools.Linker;
|
||||||
|
import org.xbib.gradle.plugin.c.toolchain.tools.StaticLibraryArchiver;
|
||||||
|
|
||||||
|
public abstract class CPlatformToolProvider implements PlatformToolProvider {
|
||||||
|
|
||||||
|
private final FileCollection tool;
|
||||||
|
|
||||||
|
private final String toolVersion;
|
||||||
|
|
||||||
|
private final String objectFileExtension;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public CPlatformToolProvider(FileCollection tool, String toolVersion, String objectFileExtension) {
|
||||||
|
this.tool = tool;
|
||||||
|
this.toolVersion = toolVersion;
|
||||||
|
this.objectFileExtension = objectFileExtension;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
public <T extends CompileSpec> Compiler<T> newCompiler(Class<T> spec) {
|
||||||
|
if (CCompileSpec.class.isAssignableFrom(spec)) {
|
||||||
|
return (Compiler<T>) createCCompiler();
|
||||||
|
}
|
||||||
|
if (AssembleSpec.class.isAssignableFrom(spec)) {
|
||||||
|
return (Compiler<T>) createAssembler();
|
||||||
|
}
|
||||||
|
if (LinkerSpec.class.isAssignableFrom(spec)) {
|
||||||
|
return (Compiler<T>) createLinker();
|
||||||
|
}
|
||||||
|
if (StaticLibraryArchiverSpec.class.isAssignableFrom(spec)) {
|
||||||
|
return (Compiler<T>) createStaticLibraryArchiver();
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException(String.format("Don't know how to compile from a spec of type %s.",
|
||||||
|
spec.getSimpleName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Compiler<CCompileSpec> createCCompiler() {
|
||||||
|
CCompiler cCompiler = new CCompiler(getBuildOperationExecutor(), getCompilerOutputFileNamingSchemeFactory(),
|
||||||
|
commandLineTool("Compiler"), context(), objectFileExtension, getWorkerLeaseService());
|
||||||
|
OutputCleaningCompiler<CCompileSpec> outputCleaningCompiler = new OutputCleaningCompiler<>(cCompiler,
|
||||||
|
getCompilerOutputFileNamingSchemeFactory(), objectFileExtension);
|
||||||
|
return versionAwareCompiler(outputCleaningCompiler, "C Compiler");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Compiler<AssembleSpec> createAssembler() {
|
||||||
|
return new Assembler(getBuildOperationExecutor(), getCompilerOutputFileNamingSchemeFactory(),
|
||||||
|
commandLineTool("Assembler"), context(), objectFileExtension, getWorkerLeaseService());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Compiler<LinkerSpec> createLinker() {
|
||||||
|
Linker linker = new Linker(getBuildOperationExecutor(), commandLineTool("Linked"), context(),
|
||||||
|
getWorkerLeaseService());
|
||||||
|
return versionAwareCompiler(linker, "Linker");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Compiler<StaticLibraryArchiverSpec> createStaticLibraryArchiver() {
|
||||||
|
return new StaticLibraryArchiver(getBuildOperationExecutor(),
|
||||||
|
commandLineTool("Static Library"), context(), getWorkerLeaseService());
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T extends CompileSpec> VersionAwareCompiler<T> versionAwareCompiler(Compiler<T> compiler, String toolType) {
|
||||||
|
return new VersionAwareCompiler<>(compiler, new DefaultCompilerVersion(toolType,
|
||||||
|
tool.getSingleFile().getName(), VersionNumber.parse(toolVersion)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private CommandLineToolInvocationWorker commandLineTool(String name) {
|
||||||
|
return new DefaultCommandLineToolInvocationWorker(name, tool.getSingleFile(), getExecActionFactory());
|
||||||
|
}
|
||||||
|
|
||||||
|
private CommandLineToolContext context() {
|
||||||
|
return new DefaultMutableCommandLineToolContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getExecutableName(String executablePath) {
|
||||||
|
return executablePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSharedLibraryName(String libraryPath) {
|
||||||
|
return libraryPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getImportLibraryName(String libraryPath) {
|
||||||
|
return libraryPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSharedLibraryLinkFileName(String libraryPath) {
|
||||||
|
return libraryPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getStaticLibraryName(String libraryPath) {
|
||||||
|
return libraryPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getExecutableSymbolFileName(String executablePath) {
|
||||||
|
return executablePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getLibrarySymbolFileName(String libraryPath) {
|
||||||
|
return libraryPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SystemLibraries getSystemLibraries(ToolType compilerType) {
|
||||||
|
return new EmptySystemLibraries();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAvailable() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSupported() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean producesImportLibrary() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean requiresDebugBinaryStripping() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void explain(DiagnosticsVisitor visitor) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getObjectFileExtension() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T get(Class<T> toolType) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompilerMetadata getCompilerMetadata(ToolType compilerType) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommandLineToolSearchResult locateTool(ToolType compilerType) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
protected abstract BuildOperationExecutor getBuildOperationExecutor();
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
protected abstract CompilerOutputFileNamingSchemeFactory getCompilerOutputFileNamingSchemeFactory();
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
protected abstract ExecActionFactory getExecActionFactory();
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
protected abstract WorkerLeaseService getWorkerLeaseService();
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
package org.xbib.gradle.plugin.c.toolchain.tools;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import org.gradle.internal.Transformers;
|
||||||
|
import org.gradle.internal.operations.BuildOperationExecutor;
|
||||||
|
import org.gradle.internal.process.ArgWriter;
|
||||||
|
import org.gradle.internal.work.WorkerLeaseService;
|
||||||
|
import org.gradle.nativeplatform.internal.CompilerOutputFileNamingSchemeFactory;
|
||||||
|
import org.gradle.nativeplatform.toolchain.internal.CommandLineToolContext;
|
||||||
|
import org.gradle.nativeplatform.toolchain.internal.CommandLineToolInvocation;
|
||||||
|
import org.gradle.nativeplatform.toolchain.internal.CommandLineToolInvocationWorker;
|
||||||
|
import org.gradle.nativeplatform.toolchain.internal.NativeCompiler;
|
||||||
|
import org.gradle.nativeplatform.toolchain.internal.compilespec.AssembleSpec;
|
||||||
|
|
||||||
|
public class Assembler extends NativeCompiler<AssembleSpec> {
|
||||||
|
|
||||||
|
private final String objectFileExtension;
|
||||||
|
|
||||||
|
public Assembler(BuildOperationExecutor buildOperationExecutor,
|
||||||
|
CompilerOutputFileNamingSchemeFactory compilerOutputFileNamingSchemeFactory,
|
||||||
|
CommandLineToolInvocationWorker commandLineTool,
|
||||||
|
CommandLineToolContext invocationContext,
|
||||||
|
String objectFileExtension,
|
||||||
|
WorkerLeaseService workerLeaseService) {
|
||||||
|
super(buildOperationExecutor, compilerOutputFileNamingSchemeFactory, commandLineTool, invocationContext,
|
||||||
|
new AssemblerArgsTransformer(), Transformers.noOpTransformer(),
|
||||||
|
objectFileExtension, true,
|
||||||
|
workerLeaseService);
|
||||||
|
|
||||||
|
this.objectFileExtension = objectFileExtension;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected CommandLineToolInvocation createPerFileInvocation(List<String> genericArgs,
|
||||||
|
File sourceFile,
|
||||||
|
File objectDir,
|
||||||
|
AssembleSpec spec) {
|
||||||
|
List<String> sourceArgs = this.getSourceArgs(sourceFile);
|
||||||
|
List<String> outputArgs = this.getOutputArgs(spec, this.getOutputFileDir(sourceFile, objectDir,
|
||||||
|
objectFileExtension));
|
||||||
|
List<String> pchArgs = this.maybeGetPCHArgs(spec, sourceFile);
|
||||||
|
|
||||||
|
// Changed order: put 'outputArgs' first
|
||||||
|
return this.newInvocation("compiling ".concat(sourceFile.getName()), objectDir,
|
||||||
|
this.buildPerFileArgs(outputArgs, genericArgs, sourceArgs, pchArgs), spec.getOperationLogger());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Iterable<String> buildPerFileArgs(List<String> genericArgs,
|
||||||
|
List<String> sourceArgs,
|
||||||
|
List<String> outputArgs,
|
||||||
|
List<String> pchArgs) {
|
||||||
|
if (pchArgs != null && !pchArgs.isEmpty()) {
|
||||||
|
throw new UnsupportedOperationException("Precompiled header arguments cannot be specified for an Assembler compiler.");
|
||||||
|
}
|
||||||
|
return super.buildPerFileArgs(genericArgs, sourceArgs, outputArgs, pchArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<String> getOutputArgs(AssembleSpec spec, File outputFile) {
|
||||||
|
return Arrays.asList("-o", outputFile.getAbsolutePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void addOptionsFileArgs(List<String> args, File tempDir) {
|
||||||
|
ArrayList<String> originalArgs = new ArrayList<>(args);
|
||||||
|
args.clear();
|
||||||
|
args.addAll(ArgWriter.argsFileGenerator(new File(tempDir, "options.txt"),
|
||||||
|
ArgWriter.unixStyleFactory()).transform(originalArgs));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<String> getPCHArgs(AssembleSpec spec) {
|
||||||
|
List<String> pchArgs = new ArrayList<>();
|
||||||
|
if (spec.getPrefixHeaderFile() != null) {
|
||||||
|
pchArgs.add("-include");
|
||||||
|
pchArgs.add(spec.getPrefixHeaderFile().getAbsolutePath());
|
||||||
|
}
|
||||||
|
return pchArgs;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
package org.xbib.gradle.plugin.c.toolchain.tools;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import org.gradle.api.NonNullApi;
|
||||||
|
import org.gradle.nativeplatform.toolchain.internal.ArgsTransformer;
|
||||||
|
import org.gradle.nativeplatform.toolchain.internal.compilespec.AssembleSpec;
|
||||||
|
|
||||||
|
@NonNullApi
|
||||||
|
public class AssemblerArgsTransformer implements ArgsTransformer<AssembleSpec> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> transform(AssembleSpec assembleSpec) {
|
||||||
|
return assembleSpec.getAllArgs();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
package org.xbib.gradle.plugin.c.toolchain.tools;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import org.gradle.internal.Transformers;
|
||||||
|
import org.gradle.internal.operations.BuildOperationExecutor;
|
||||||
|
import org.gradle.internal.process.ArgWriter;
|
||||||
|
import org.gradle.internal.work.WorkerLeaseService;
|
||||||
|
import org.gradle.nativeplatform.internal.CompilerOutputFileNamingSchemeFactory;
|
||||||
|
import org.gradle.nativeplatform.toolchain.internal.CommandLineToolContext;
|
||||||
|
import org.gradle.nativeplatform.toolchain.internal.CommandLineToolInvocation;
|
||||||
|
import org.gradle.nativeplatform.toolchain.internal.CommandLineToolInvocationWorker;
|
||||||
|
import org.gradle.nativeplatform.toolchain.internal.NativeCompiler;
|
||||||
|
import org.gradle.nativeplatform.toolchain.internal.compilespec.CCompileSpec;
|
||||||
|
import org.xbib.gradle.plugin.c.tasks.ExtendedCCompileSpec;
|
||||||
|
|
||||||
|
public class CCompiler extends NativeCompiler<CCompileSpec> {
|
||||||
|
|
||||||
|
public CCompiler(BuildOperationExecutor buildOperationExecutor,
|
||||||
|
CompilerOutputFileNamingSchemeFactory compilerOutputFileNamingSchemeFactory,
|
||||||
|
CommandLineToolInvocationWorker commandLineToolInvocationWorker,
|
||||||
|
CommandLineToolContext invocationContext,
|
||||||
|
String objectFileExtension,
|
||||||
|
WorkerLeaseService workerLeaseService) {
|
||||||
|
super(buildOperationExecutor, compilerOutputFileNamingSchemeFactory, commandLineToolInvocationWorker, invocationContext,
|
||||||
|
new CCompilerArgsTransformer(), Transformers.noOpTransformer(),
|
||||||
|
objectFileExtension, true, workerLeaseService);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<String> getOutputArgs(CCompileSpec spec, File outputFile) {
|
||||||
|
return Arrays.asList("-o", outputFile.getAbsolutePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void addOptionsFileArgs(List<String> args, File tempDir) {
|
||||||
|
ArrayList<String> originalArgs = new ArrayList<>(args);
|
||||||
|
args.clear();
|
||||||
|
args.addAll(ArgWriter.argsFileGenerator(new File(tempDir, "options.txt"),
|
||||||
|
ArgWriter.unixStyleFactory()).transform(originalArgs));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<String> getPCHArgs(CCompileSpec spec) {
|
||||||
|
List<String> pchArgs = new ArrayList<>();
|
||||||
|
if (spec.getPrefixHeaderFile() != null) {
|
||||||
|
pchArgs.add("-include");
|
||||||
|
pchArgs.add(spec.getPrefixHeaderFile().getAbsolutePath());
|
||||||
|
}
|
||||||
|
return pchArgs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected CommandLineToolInvocation createPerFileInvocation(List<String> genericArgs,
|
||||||
|
File sourceFile,
|
||||||
|
File objectDir,
|
||||||
|
CCompileSpec spec) {
|
||||||
|
ExtendedCCompileSpec extendedCCompileSpec = (ExtendedCCompileSpec) spec;
|
||||||
|
List<String> perFileArgs = extendedCCompileSpec.getPerFileCompilerArgs().get(sourceFile.getName());
|
||||||
|
if (perFileArgs != null) {
|
||||||
|
List<String> allPerFileArgs = new ArrayList<>(genericArgs);
|
||||||
|
allPerFileArgs.addAll(perFileArgs);
|
||||||
|
return super.createPerFileInvocation(allPerFileArgs, sourceFile, objectDir, spec);
|
||||||
|
} else {
|
||||||
|
return super.createPerFileInvocation(genericArgs, sourceFile, objectDir, spec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
package org.xbib.gradle.plugin.c.toolchain.tools;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import org.gradle.api.NonNullApi;
|
||||||
|
import org.gradle.nativeplatform.toolchain.internal.ArgsTransformer;
|
||||||
|
import org.gradle.nativeplatform.toolchain.internal.MacroArgsConverter;
|
||||||
|
import org.gradle.nativeplatform.toolchain.internal.compilespec.CCompileSpec;
|
||||||
|
|
||||||
|
@NonNullApi
|
||||||
|
public class CCompilerArgsTransformer implements ArgsTransformer<CCompileSpec> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> transform(CCompileSpec spec) {
|
||||||
|
List<String> args = new ArrayList<>();
|
||||||
|
|
||||||
|
for (File file : spec.getIncludeRoots()) {
|
||||||
|
args.add("-I");
|
||||||
|
args.add(file.getAbsolutePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (File file : spec.getSystemIncludeRoots()) {
|
||||||
|
args.add("-isystem");
|
||||||
|
args.add(file.getAbsolutePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String macroArg : new MacroArgsConverter().transform(spec.getMacros())) {
|
||||||
|
args.add("-D" + macroArg);
|
||||||
|
}
|
||||||
|
args.addAll(spec.getAllArgs());
|
||||||
|
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
package org.xbib.gradle.plugin.c.toolchain.tools;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import org.gradle.api.Action;
|
||||||
|
import org.gradle.internal.operations.BuildOperationExecutor;
|
||||||
|
import org.gradle.internal.operations.BuildOperationQueue;
|
||||||
|
import org.gradle.internal.process.ArgWriter;
|
||||||
|
import org.gradle.internal.work.WorkerLeaseService;
|
||||||
|
import org.gradle.nativeplatform.internal.LinkerSpec;
|
||||||
|
import org.gradle.nativeplatform.toolchain.internal.AbstractCompiler;
|
||||||
|
import org.gradle.nativeplatform.toolchain.internal.CommandLineToolContext;
|
||||||
|
import org.gradle.nativeplatform.toolchain.internal.CommandLineToolInvocation;
|
||||||
|
import org.gradle.nativeplatform.toolchain.internal.CommandLineToolInvocationWorker;
|
||||||
|
|
||||||
|
public class Linker extends AbstractCompiler<LinkerSpec> {
|
||||||
|
|
||||||
|
public Linker(BuildOperationExecutor buildOperationExecutor,
|
||||||
|
CommandLineToolInvocationWorker commandLineToolInvocationWorker,
|
||||||
|
CommandLineToolContext invocationContext,
|
||||||
|
WorkerLeaseService workerLeaseService) {
|
||||||
|
super(buildOperationExecutor, commandLineToolInvocationWorker, invocationContext,
|
||||||
|
new LinkerArgsTransformer(),
|
||||||
|
true, workerLeaseService);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Action<BuildOperationQueue<CommandLineToolInvocation>> newInvocationAction(final LinkerSpec spec,
|
||||||
|
List<String> args) {
|
||||||
|
final CommandLineToolInvocation invocation = newInvocation("linking " + spec.getOutputFile().getName(),
|
||||||
|
args, spec.getOperationLogger());
|
||||||
|
return buildQueue -> {
|
||||||
|
buildQueue.setLogLocation(spec.getOperationLogger().getLogLocation());
|
||||||
|
buildQueue.add(invocation);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void addOptionsFileArgs(List<String> args, File tempDir) {
|
||||||
|
ArrayList<String> originalArgs = new ArrayList<>(args);
|
||||||
|
args.clear();
|
||||||
|
args.addAll(ArgWriter.argsFileGenerator(new File(tempDir, "options.txt"),
|
||||||
|
ArgWriter.unixStyleFactory()).transform(originalArgs));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package org.xbib.gradle.plugin.c.toolchain.tools;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import org.gradle.api.NonNullApi;
|
||||||
|
import org.gradle.nativeplatform.internal.LinkerSpec;
|
||||||
|
import org.gradle.nativeplatform.toolchain.internal.ArgsTransformer;
|
||||||
|
|
||||||
|
@NonNullApi
|
||||||
|
public class LinkerArgsTransformer implements ArgsTransformer<LinkerSpec> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> transform(LinkerSpec spec) {
|
||||||
|
|
||||||
|
List<String> args = new ArrayList<>(spec.getSystemArgs());
|
||||||
|
|
||||||
|
args.addAll(spec.getArgs());
|
||||||
|
|
||||||
|
for (File file : spec.getObjectFiles()) {
|
||||||
|
args.add(file.getAbsolutePath());
|
||||||
|
}
|
||||||
|
for (File file : spec.getLibraries()) {
|
||||||
|
args.add(file.getAbsolutePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
args.add("-o");
|
||||||
|
args.add(spec.getOutputFile().getAbsolutePath());
|
||||||
|
|
||||||
|
if (!spec.getLibraryPath().isEmpty()) {
|
||||||
|
throw new UnsupportedOperationException("Library Path not yet supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
package org.xbib.gradle.plugin.c.toolchain.tools;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.List;
|
||||||
|
import org.gradle.api.Action;
|
||||||
|
import org.gradle.api.GradleException;
|
||||||
|
import org.gradle.api.tasks.WorkResult;
|
||||||
|
import org.gradle.internal.operations.BuildOperationExecutor;
|
||||||
|
import org.gradle.internal.operations.BuildOperationQueue;
|
||||||
|
import org.gradle.internal.work.WorkerLeaseService;
|
||||||
|
import org.gradle.nativeplatform.internal.StaticLibraryArchiverSpec;
|
||||||
|
import org.gradle.nativeplatform.toolchain.internal.AbstractCompiler;
|
||||||
|
import org.gradle.nativeplatform.toolchain.internal.CommandLineToolContext;
|
||||||
|
import org.gradle.nativeplatform.toolchain.internal.CommandLineToolInvocation;
|
||||||
|
import org.gradle.nativeplatform.toolchain.internal.CommandLineToolInvocationWorker;
|
||||||
|
|
||||||
|
public class StaticLibraryArchiver extends AbstractCompiler<StaticLibraryArchiverSpec> {
|
||||||
|
|
||||||
|
public StaticLibraryArchiver(BuildOperationExecutor buildOperationExecutor,
|
||||||
|
CommandLineToolInvocationWorker commandLineToolInvocationWorker,
|
||||||
|
CommandLineToolContext invocationContext,
|
||||||
|
WorkerLeaseService workerLeaseService) {
|
||||||
|
super(buildOperationExecutor, commandLineToolInvocationWorker, invocationContext,
|
||||||
|
new StaticLibraryArchiverArgsTransformer(), false, workerLeaseService);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WorkResult execute(final StaticLibraryArchiverSpec spec) {
|
||||||
|
deletePreviousOutput(spec);
|
||||||
|
return super.execute(spec);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void deletePreviousOutput(StaticLibraryArchiverSpec spec) {
|
||||||
|
// Need to delete the previous archive, otherwise stale object files will remain
|
||||||
|
if (!spec.getOutputFile().isFile()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!(spec.getOutputFile().delete())) {
|
||||||
|
throw new GradleException("Create static archive failed: could not delete previous archive");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Action<BuildOperationQueue<CommandLineToolInvocation>> newInvocationAction(final StaticLibraryArchiverSpec spec,
|
||||||
|
List<String> args) {
|
||||||
|
final CommandLineToolInvocation invocation = newInvocation(
|
||||||
|
"archiving " + spec.getOutputFile().getName(), spec.getOutputFile().getParentFile(), args, spec.getOperationLogger());
|
||||||
|
|
||||||
|
return buildQueue -> {
|
||||||
|
buildQueue.setLogLocation(spec.getOperationLogger().getLogLocation());
|
||||||
|
buildQueue.add(invocation);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void addOptionsFileArgs(List<String> args, File tempDir) {
|
||||||
|
// No support for command file
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
package org.xbib.gradle.plugin.c.toolchain.tools;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import org.gradle.api.NonNullApi;
|
||||||
|
import org.gradle.nativeplatform.internal.StaticLibraryArchiverSpec;
|
||||||
|
import org.gradle.nativeplatform.toolchain.internal.ArgsTransformer;
|
||||||
|
|
||||||
|
@NonNullApi
|
||||||
|
public class StaticLibraryArchiverArgsTransformer implements ArgsTransformer<StaticLibraryArchiverSpec> {
|
||||||
|
|
||||||
|
public List<String> transform(StaticLibraryArchiverSpec spec) {
|
||||||
|
List<String> args = new ArrayList<>(spec.getAllArgs());
|
||||||
|
|
||||||
|
args.add("-rv");
|
||||||
|
|
||||||
|
args.add(spec.getOutputFile().getAbsolutePath());
|
||||||
|
|
||||||
|
for (File file : spec.getObjectFiles()) {
|
||||||
|
args.add(file.getAbsolutePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
package org.xbib.gradle.plugin.c.toolchain.transform;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.attribute.PosixFilePermissions;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipInputStream;
|
||||||
|
import org.gradle.api.artifacts.transform.InputArtifact;
|
||||||
|
import org.gradle.api.artifacts.transform.TransformAction;
|
||||||
|
import org.gradle.api.artifacts.transform.TransformOutputs;
|
||||||
|
import org.gradle.api.artifacts.transform.TransformParameters;
|
||||||
|
import org.gradle.api.file.FileSystemLocation;
|
||||||
|
import org.gradle.api.provider.Provider;
|
||||||
|
import org.gradle.api.tasks.PathSensitive;
|
||||||
|
import org.gradle.api.tasks.PathSensitivity;
|
||||||
|
import org.gradle.internal.os.OperatingSystem;
|
||||||
|
|
||||||
|
public abstract class ExtractZipTransform implements TransformAction<TransformParameters.None> {
|
||||||
|
|
||||||
|
@InputArtifact
|
||||||
|
@PathSensitive(PathSensitivity.RELATIVE)
|
||||||
|
public abstract Provider<FileSystemLocation> getInputArtifact();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void transform(TransformOutputs outputs) {
|
||||||
|
File input = getInputArtifact().get().getAsFile();
|
||||||
|
File unzipDir = outputs.dir(input.getName().substring(0, input.getName().lastIndexOf(".zip")));
|
||||||
|
try {
|
||||||
|
unzipTo(input, unzipDir);
|
||||||
|
System.out.println("Transformed into: " + unzipDir.getAbsolutePath());
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void unzipTo(File input, File unzipDir) throws IOException {
|
||||||
|
byte[] buffer = new byte[1024];
|
||||||
|
ZipInputStream zis = new ZipInputStream(Files.newInputStream(input.toPath()));
|
||||||
|
ZipEntry zipEntry = zis.getNextEntry();
|
||||||
|
|
||||||
|
while (zipEntry != null) {
|
||||||
|
if (!zipEntry.isDirectory()) {
|
||||||
|
File newFile = new File(unzipDir, zipEntry.getName());
|
||||||
|
newFile.getParentFile().mkdirs();
|
||||||
|
FileOutputStream fos = new FileOutputStream(newFile);
|
||||||
|
int len;
|
||||||
|
while ((len = zis.read(buffer)) > 0) {
|
||||||
|
fos.write(buffer, 0, len);
|
||||||
|
}
|
||||||
|
fos.close();
|
||||||
|
if (OperatingSystem.current().isUnix()) {
|
||||||
|
Files.setPosixFilePermissions(newFile.toPath(), PosixFilePermissions.fromString("rwxr-xr-x"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
zipEntry = zis.getNextEntry();
|
||||||
|
}
|
||||||
|
|
||||||
|
zis.closeEntry();
|
||||||
|
zis.close();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
package org.xbib.gradle.plugin.c.test
|
||||||
|
|
||||||
|
import org.gradle.testkit.runner.BuildResult
|
||||||
|
import org.gradle.testkit.runner.GradleRunner
|
||||||
|
import org.gradle.testkit.runner.TaskOutcome
|
||||||
|
import org.junit.jupiter.api.BeforeEach
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
import org.junit.jupiter.api.io.TempDir
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals
|
||||||
|
|
||||||
|
class CPluginIntegrationTest {
|
||||||
|
|
||||||
|
private File projectDir
|
||||||
|
|
||||||
|
private File settingsFile
|
||||||
|
|
||||||
|
private File buildFile
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setup(@TempDir File testProjectDir) throws IOException {
|
||||||
|
this.projectDir = testProjectDir
|
||||||
|
this.settingsFile = new File(testProjectDir, "settings.gradle")
|
||||||
|
this.buildFile = new File(testProjectDir, "build.gradle")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testPlugin() {
|
||||||
|
String settingsFileContent = '''
|
||||||
|
rootProject.name = 'c-test'
|
||||||
|
'''
|
||||||
|
settingsFile.write(settingsFileContent)
|
||||||
|
String buildFileContent = '''
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id 'base'
|
||||||
|
id 'org.xbib.gradle.plugin.c'
|
||||||
|
}
|
||||||
|
|
||||||
|
// dummy task, no source present
|
||||||
|
|
||||||
|
tasks.register('compileC', org.xbib.gradle.plugin.c.tasks.ExtendedCCompile) {
|
||||||
|
toolChain.set(c.localTool("14.0.0", "/usr/bin/clang", ".o"))
|
||||||
|
targetPlatform.set(c.platform())
|
||||||
|
source(layout.projectDirectory.files("src/c").asFileTree)
|
||||||
|
includes(layout.projectDirectory.files("src/headers"))
|
||||||
|
compilerArgs.add("-S")
|
||||||
|
objectFileDir.set(layout.buildDirectory.dir("out/o"))
|
||||||
|
}
|
||||||
|
|
||||||
|
'''
|
||||||
|
buildFile.write(buildFileContent)
|
||||||
|
BuildResult result = GradleRunner.create()
|
||||||
|
.withProjectDir(projectDir)
|
||||||
|
.withPluginClasspath()
|
||||||
|
.withArguments(":compileC", "--info", "--stacktrace", "--warning-mode=all")
|
||||||
|
.forwardOutput()
|
||||||
|
.build()
|
||||||
|
assertEquals(TaskOutcome.NO_SOURCE, result.task(":compileC").getOutcome())
|
||||||
|
}
|
||||||
|
}
|
8
gradle-plugin-cmake/NOTICE.txt
Normal file
8
gradle-plugin-cmake/NOTICE.txt
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
|
||||||
|
This work is based on
|
||||||
|
|
||||||
|
https://github.com/crimsonmagick/gradle-cmake-plugin
|
||||||
|
|
||||||
|
as of Januar 8, 2024
|
||||||
|
|
||||||
|
License: Apache 2.0
|
185
gradle-plugin-cmake/README.md
Normal file
185
gradle-plugin-cmake/README.md
Normal file
|
@ -0,0 +1,185 @@
|
||||||
|
# gradle-plugin-cmake
|
||||||
|
|
||||||
|
This plugin allows to configure and build using CMake.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
* `CMake` installed on the system. Available [here](https://www.cmake.org "CMake Homepage").
|
||||||
|
|
||||||
|
## To apply the plugin:
|
||||||
|
|
||||||
|
**plugins DSL**
|
||||||
|
|
||||||
|
```groovy
|
||||||
|
plugins {
|
||||||
|
id 'org.xbib.gradle.plugin.cmake' version '3.1.0'
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Legacy plugin application**
|
||||||
|
|
||||||
|
```groovy
|
||||||
|
buildscript {
|
||||||
|
repositories {
|
||||||
|
maven {
|
||||||
|
url "https://plugins.gradle.org/m2/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dependencies {
|
||||||
|
classpath 'org.xbib.gradle:gradle-plugin-cmake:3.1.0'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
apply plugin: "org.xbib.gradle.plugin.cmake"
|
||||||
|
```
|
||||||
|
|
||||||
|
and configure by:
|
||||||
|
|
||||||
|
```groovy
|
||||||
|
cmake {
|
||||||
|
// optional configration to path of cmake. Not required if cmake is on the path.
|
||||||
|
executable='/my/path/to/cmake'
|
||||||
|
// optional working folder. default is ./build/cmake
|
||||||
|
workingFolder=file("$buildDir/cmake")
|
||||||
|
// cmakeConfigure parameters
|
||||||
|
// optional source folder. This is where the main CMakeLists.txt file resides. Default is ./src/main/cpp
|
||||||
|
sourceFolder=file("$projectDir/src/main/cpp")
|
||||||
|
// optional install prefix. By default, install prefix is empty.
|
||||||
|
installPrefix="${System.properties['user.home']}"
|
||||||
|
// select a generator (optional, otherwise cmake's default generator is used)
|
||||||
|
generator='Visual Studio 15 2017'
|
||||||
|
// set a platform for generators that support it (usually Visual Studio)
|
||||||
|
platform='x64'
|
||||||
|
// set a toolset generators that support it (usually only Visual Studio)
|
||||||
|
toolset='v141'
|
||||||
|
// optionally set to build static libs
|
||||||
|
buildStaticLibs=true
|
||||||
|
// optionally set to build shared libs
|
||||||
|
buildSharedLibs=true
|
||||||
|
// define arbitrary CMake parameters. The below adds -Dtest=hello to cmake command line.
|
||||||
|
defs.test='hello'
|
||||||
|
// cmakeBuild parameters
|
||||||
|
// optional configuration to build
|
||||||
|
buildConfig='Release'
|
||||||
|
// optional build target
|
||||||
|
buildTarget='install'
|
||||||
|
// optional build clean. if set to true, calls cmake --build with --clean-first
|
||||||
|
buildClean=false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Auto-created tasks
|
||||||
|
|
||||||
|
* *cmakeConfigure*: Calls CMake to generate your build scripts in the folder selected by workingFolder.
|
||||||
|
|
||||||
|
* *cmakeBuild*: Calls CMake --build in the folder selected by workingFolder to actually build.
|
||||||
|
|
||||||
|
* *cmakeClean*: Cleans the workingFolder.
|
||||||
|
|
||||||
|
* *cmakeGenerators*: Trys to list the generators available on the current platform by parsing `cmake --help`'s output.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
clean, configure and build:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./gradlew cmakeClean cmakeConfigure cmakeBuild
|
||||||
|
```
|
||||||
|
|
||||||
|
if you have assemble and clean tasks in your gradle project already you can also use:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
assemble.dependsOn cmakeBuild
|
||||||
|
cmakeBuild.dependsOn cmakeConfigure
|
||||||
|
clean.dependsOn cmakeClean
|
||||||
|
```
|
||||||
|
|
||||||
|
and just call
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./gradlew clean assemble
|
||||||
|
```
|
||||||
|
|
||||||
|
If you want to get the output of cmake, add -i to your gradle call, for example:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./gradlew cmakeConfigure -i
|
||||||
|
```
|
||||||
|
|
||||||
|
## Custom tasks
|
||||||
|
|
||||||
|
You can create custom tasks the following way:
|
||||||
|
|
||||||
|
```groovy
|
||||||
|
task configureFoo(type: org.xbib.gradle.plugin.cmake.CMakeConfigureTask) {
|
||||||
|
sourceFolder=file("$projectDir/src/main/cpp/foo")
|
||||||
|
workingFolder=file("$buildDir/cmake/foo")
|
||||||
|
// ... other parameters you need, see above, except the ones listed under cmakeBuild Parameters
|
||||||
|
}
|
||||||
|
|
||||||
|
task buildFoo(type: org.xbib.gradle.plugin.cmake.CMakeBuildTask) {
|
||||||
|
workingFolder=file("$buildDir/cmake/foo")
|
||||||
|
// ... other parameters you need, see above, except the ones listed under cmakeConfigure parameters
|
||||||
|
}
|
||||||
|
|
||||||
|
buildFoo.dependsOn configureFoo // optional --- make sure its configured when you run the build task
|
||||||
|
```
|
||||||
|
### Multiple targets (cross-compilation)
|
||||||
|
If you need to configure for multiple targets you can use the `targets` property:
|
||||||
|
|
||||||
|
```groovy
|
||||||
|
cmake {
|
||||||
|
sourceFolder = "$projectDir/src"
|
||||||
|
buildSharedLibs = true
|
||||||
|
buildClean = true
|
||||||
|
buildConfig = 'Release'
|
||||||
|
targets {
|
||||||
|
windows {
|
||||||
|
final os = OperatingSystem.WINDOWS
|
||||||
|
workingFolder = new File(project.getBuildDir(), "cmake" + File.separator + os.nativePrefix)
|
||||||
|
platform='x64'
|
||||||
|
}
|
||||||
|
linux {
|
||||||
|
final os = OperatingSystem.LINUX
|
||||||
|
workingFolder = new File(project.getBuildDir(), "cmake" + File.separator + os.nativePrefix)
|
||||||
|
platform = 'x64'
|
||||||
|
}
|
||||||
|
mac {
|
||||||
|
final os = OperatingSystem.MAC_OS
|
||||||
|
workingFolder = new File(project.getBuildDir(), "cmake" + File.separator + os.nativePrefix)
|
||||||
|
platform = 'arm64'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Custom tasks using main configuration
|
||||||
|
|
||||||
|
As an alternative to using `targets` you can "import" the settings you've made in the main configuration "cmake" using the 'configureFromProject()' call:
|
||||||
|
|
||||||
|
```groovy
|
||||||
|
cmake {
|
||||||
|
executable='/my/path/to/cmake'
|
||||||
|
workingFolder=file("$buildDir/cmake")
|
||||||
|
sourceFolder=file("$projectDir/src/main/cpp")
|
||||||
|
installPrefix="${System.properties['user.home']}"
|
||||||
|
generator='Visual Studio 15 2017'
|
||||||
|
platform='x64'
|
||||||
|
}
|
||||||
|
|
||||||
|
task cmakeConfigureX86(type: org.xbib.gradle.plugin.cmake.CMakeConfigureTask) {
|
||||||
|
configureFromProject() // uses everything in the cmake { ... } section.
|
||||||
|
// overwrite target platform
|
||||||
|
platform='x86'
|
||||||
|
// set a different working folder to not collide with default task
|
||||||
|
workingFolder=file("$buildDir/cmake_x86")
|
||||||
|
}
|
||||||
|
|
||||||
|
task cmakeBuildX86(type: org.xbib.gradle.plugin.cmake.CMakeBuildTask) {
|
||||||
|
configureFromProject() // uses everything in the cmake { ... } section.
|
||||||
|
workingFolder=file("$buildDir/cmake_x86")
|
||||||
|
}
|
||||||
|
|
||||||
|
cmakeBuildX86.dependsOn cmakeConfigureX86
|
||||||
|
```
|
|
@ -4,7 +4,7 @@ plugins {
|
||||||
|
|
||||||
apply plugin: 'com.gradle.plugin-publish'
|
apply plugin: 'com.gradle.plugin-publish'
|
||||||
|
|
||||||
apply from: rootProject.file('gradle/compile/java.gradle')
|
apply from: rootProject.file('gradle/compile/groovy.gradle')
|
||||||
apply from: rootProject.file('gradle/test/junit5.gradle')
|
apply from: rootProject.file('gradle/test/junit5.gradle')
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
package org.xbib.gradle.plugin.cmake.test
|
||||||
|
|
||||||
|
import org.gradle.testkit.runner.BuildResult
|
||||||
|
import org.gradle.testkit.runner.GradleRunner
|
||||||
|
import org.gradle.testkit.runner.TaskOutcome
|
||||||
|
import org.junit.jupiter.api.BeforeEach
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
import org.junit.jupiter.api.io.TempDir
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals
|
||||||
|
|
||||||
|
class CmakePluginIntegrationTest {
|
||||||
|
|
||||||
|
private File projectDir
|
||||||
|
|
||||||
|
private File settingsFile
|
||||||
|
|
||||||
|
private File buildFile
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setup(@TempDir File testProjectDir) throws IOException {
|
||||||
|
this.projectDir = testProjectDir
|
||||||
|
File f = new File(testProjectDir, 'build/src/main/cpp')
|
||||||
|
f.mkdirs()
|
||||||
|
File cmakeList = new File(f, 'CMakeLists.txt')
|
||||||
|
cmakeList.write('')
|
||||||
|
this.settingsFile = new File(testProjectDir, "settings.gradle")
|
||||||
|
this.buildFile = new File(testProjectDir, "build.gradle")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testPlugin() {
|
||||||
|
String settingsFileContent = '''
|
||||||
|
rootProject.name = 'cmake-test'
|
||||||
|
'''
|
||||||
|
settingsFile.write(settingsFileContent)
|
||||||
|
String buildFileContent = '''
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id 'org.xbib.gradle.plugin.cmake'
|
||||||
|
}
|
||||||
|
|
||||||
|
'''
|
||||||
|
buildFile.write(buildFileContent)
|
||||||
|
BuildResult result = GradleRunner.create()
|
||||||
|
.withProjectDir(projectDir)
|
||||||
|
.withPluginClasspath()
|
||||||
|
.withArguments(":cmakeConfigure", "--info", "--stacktrace", "--warning-mode=all")
|
||||||
|
.forwardOutput()
|
||||||
|
.build()
|
||||||
|
assertEquals(TaskOutcome.SUCCESS, result.task(":cmakeConfigure").getOutcome())
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ dependencyResolutionManagement {
|
||||||
libs {
|
libs {
|
||||||
version('gradle', '8.5')
|
version('gradle', '8.5')
|
||||||
version('groovy', '3.0.17') // MUST match gradle groovy version
|
version('groovy', '3.0.17') // MUST match gradle groovy version
|
||||||
|
// Java 21
|
||||||
version('asm', '9.6')
|
version('asm', '9.6')
|
||||||
// Attention: it is impossible to develop a gradle plugin with groovy 4!
|
// Attention: it is impossible to develop a gradle plugin with groovy 4!
|
||||||
// The gradle plugin publish plugin enforces java-gradle-plugin,
|
// The gradle plugin publish plugin enforces java-gradle-plugin,
|
||||||
|
@ -42,6 +43,7 @@ dependencyResolutionManagement {
|
||||||
}
|
}
|
||||||
|
|
||||||
include 'gradle-plugin-asciidoctor'
|
include 'gradle-plugin-asciidoctor'
|
||||||
|
include 'gradle-plugin-c'
|
||||||
include 'gradle-plugin-cmake'
|
include 'gradle-plugin-cmake'
|
||||||
include 'gradle-plugin-docker'
|
include 'gradle-plugin-docker'
|
||||||
include 'gradle-plugin-git'
|
include 'gradle-plugin-git'
|
||||||
|
|
Loading…
Reference in a new issue