代码之家  ›  专栏  ›  技术社区  ›  Tudor Timi

在新语言插件中将编译器参数设置为字符串列表

  •  2
  • Tudor Timi  · 技术社区  · 7 年前

    我正在为一种新语言开发一个插件,并试图向编译器添加对编译选项的支持。我使用了 org.gradle.api.tasks.compile.CompileOptions 类作为起点,并实现了我自己的类,如下所示:

    class SvCompileOptions extends AbstractOptions {
        private List<String> compilerArgs = Lists.newArrayList();
    
        @Input
        public List<String> getCompilerArgs() {
            return compilerArgs;
        }
    
        public void setCompilerArgs(List<String> compilerArgs) {
            this.compilerArgs = compilerArgs;
        }
    }
    

    在我的构建中。gradle文件,我尝试了以下操作:

    compileSv {
        options.compilerArgs += [ "-foo" ]
    }
    

    (compileSv是一个具有SvCompileOptions类型的options属性的任务。)

    我得到以下错误:

    A problem occurred evaluating project ':uvc2'.
    > java.lang.AbstractMethodError (no error message)
    

    如果我将该行替换为:

    compileSv {
        options.compilerArgs.add("-foo")
    }
    

    然后一切都很好,但不是很有层次感。

    有人能指出我做错了什么吗?


    根据@tim\u yates的建议,我添加了一个函数来附加到 compilerArgs :

    class SvCompileOptions extends AbstractOptions {
    
        void compilerArgs(String... args) {
            this.compilerArgs.addAll(args as List)
        }
    }
    

    根据@Opal的建议,我创建了一个赤裸裸的示例:

    // File 'build.gradle'
    
    buildscript {
        dependencies {
            classpath 'com.google.guava:guava:16+'
        }
        repositories {
            mavenCentral()
        }
    }
    
    import com.google.common.collect.ImmutableSet;
    import com.google.common.collect.Lists;
    
    
    class SvCompileOptions extends AbstractOptions {
    
        private List<String> compilerArgs = Lists.newArrayList();
    
        @Input
        public List<String> getCompilerArgs() {
            return compilerArgs;
        }
    
        public void setCompilerArgs(List<String> compilerArgs) {
            this.compilerArgs = compilerArgs;
        }
    
        void compilerArgs(String... args) {
            this.compilerArgs.addAll(args as List)
        }
    
    }
    
    
    class SvCompile extends DefaultTask {
    
        @TaskAction
        protected void compile() {
            println options.compilerArgs
        }
    
        @Nested
        SvCompileOptions options = new SvCompileOptions()
    
    }
    
    
    task compileSv(type: SvCompile)
    
    
    compileSv {
        options.compilerArgs 'foo', 'bar'
    }
    

    代码将参数附加到空列表并打印 [foo, bar] 正如所料。如果我们尝试使用以下内容覆盖参数:

    compileSv {
        options.compilerArgs = ['one', 'two']
    }
    

    将打印错误消息:

    * What went wrong:
    A problem occurred evaluating root project 'so_compile_options2'.
    > SvCompileOptions.setProperty(Ljava/lang/String;Ljava/lang/Object;)V
    

    我不知道当类内联在中时,错误消息为什么会不同 build.gradle ,但我想这就是导致 AbstractMethodError 我看到了。

    正如@Opal指出的,这个问题是由于在 AbstractOptions 班我尝试将以下方法添加到compile options类,但错误消息仍然存在:

    class SvCompileOptions extends AbstractOptions {
    
        private static final ImmutableSet<String> EXCLUDE_FROM_ANT_PROPERTIES =
                ImmutableSet.of("compilerArgs");
    
        @Override
        protected boolean excludeFromAntProperties(String fieldName) {
            return EXCLUDE_FROM_ANT_PROPERTIES.contains(fieldName);
        }
    
        // ...
    }
    

    exclude函数似乎根本没有被调用,就像我在其中添加了一个伪打印一样,它永远不会被发出。

    2 回复  |  直到 7 年前
        1
  •  1
  •   tim_yates    7 年前

    这应该行得通

    options.compilerArgs << "-foo"
    

    如果要添加多个值(可能在某个时候会这样做),一种惯用的方法是将类更改为:

    class SvCompileOptions extends AbstractOptions {
        @Input
        List<String> compilerArgs = Lists.newArrayList();
    
        def args(String... args) {
            this.compilerArgs += args.toList()
        }
    }
    

    然后,您可以执行以下操作:

    compileSv {
        options.args "-foo", "-bar"
    }
    
        2
  •  1
  •   Tudor Timi    7 年前

    在@Opal的宝贵见解之后 AbstractOptions 是问题的根源,并在Gradle Github页面上找到与以下内容相关的问题 removing the AbstractOptions class altogether ,我认为最好的做法是根本不使用基类。

    在集成了@tim\u yates对“append”方法的建议后,我将执行以下实现:

    class SvCompileOptions {
    
        private List<String> compilerArgs = Lists.newArrayList();
    
        @Input
        public List<String> getCompilerArgs() {
            return compilerArgs;
        }
    
        // Overwrites
        public void setCompilerArgs(List<String> compilerArgs) {
            this.compilerArgs = compilerArgs;
        }
    
        // Appends
        void compilerArgs(String... args) {
            this.compilerArgs.addAll(args as List)
        }
    
    }
    

    这允许用户附加参数:

    compileSv {
        options.compilerArgs 'foo', 'bar'
    }
    

    并覆盖它们:

    compileSv {
        options.compilerArgs = ['one', 'two']
    }