樹脂が固まる前に

AndroidとWebフロントエンドを主にいじっている学生のメモ

Kotlin/Native v0.3がWin対応したので触ってみた

はじめに

全ての道はKotlinに通ず

つい先日,Kotlin/Nativeがv0.3になってwindowsで動くようになったらしい. blog.jetbrains.com 触るしか無い…!

はじめに結果を言っとくと,サンプルを動かしてウィンドウが出せたよ f:id:pvcresin:20170624012016p:plain

準備

環境はwindows10 64bit.
上のリンクからx86-64 Windows用のzipを落としてきて解凍する.
中はこんな感じ
f:id:pvcresin:20170624011856p:plain
このbinにPATHを通す.(再起動も忘れずに)

何となくコマンドプロンプト(以下cmd)でkotlincと打つと,
Downloading native dependencies (LLVM, sysroot etc). This is a one-time action performed only on the first run of the compiler.
なるほど.はじめは何か落としてくるのか.350MBだったので,まぁまぁ待った.
色々落としてきてる様子がコンソールに流れて,終わったと思ったら最後に
error: you have not specified any compilation arguments. No output has been produced.
怒られた.まぁそうだよね.kotlinc のあとファイル指定してないし.

よしこれで準備OK!

README.mdとか読みながら動かしていくぞ

exeを書き出してみる

hello.ktを作成

fun main(args: Array<String>) {
  for (i in 0 until 10000) {
    println("hello kotlin native :$i")
  }
}

cmdでコンパイルタイム!
README.md によるとkotlinc hello.kt -o helloって書いてあったけど,
これだと怒られるので,kotlinc-native hello.kt -o helloってやったらhello.exeとhello.kt.bcが出来た.
exeをクリックして実行すると文字が流れる.OK!

win32APIを使ってウィンドウを生成する

これが本番.同封されているサンプルにwin32というのがあるのでこれを動かす
サンプルからコードをコピってくる

hello.kt

import win32.*

fun main(args: Array<String>) {
    MessageBoxW(null, "Konan говорит:\nЗДРАВСТВУЙ МИР!\n",
            "Заголовок окна", MB_YESNOCANCEL or MB_ICONQUESTION)
}

キリル文字が並んでる~と思ったら,あ~JetBrainsはロシアだっけか(チェコでした)。

サンプルからwin32.defもコピってきて,コマンドを打つ
cinterop -def win32.def -o win32
数分かかったが,win32-buildというフォルダとwin32.klibができた. これでライブラリの準備が出来たっぽい
ちなみにklibはv0.3から出来たライブラリのフォーマットらしい.

kotlinc-native hello.kt -library win32 -o hello
コンパイルして,出来たhello.exeをクリックすると~

f:id:pvcresin:20170624012016p:plain

すごい.どことなくウイルスみたいに見えるけど,サンプル動いた.おわり!

おわりに

ここからは独り言なんだけど,Kotlinすごい(自分の周りで騒いでる人いなくて悲しいんだけど)

JVMで実行できて,JSへの変換も公式になって,Nativeにも書き出せて,Android開発の公式言語になった
コミュニティのロゴとかも出来たね
Cとかの代わりになるってことでいいのかな?この流れで行くとWebAssemblyまで手を出しそうだ.というか出すんじゃないかな

あと,今回のv0.3でAndroidのnative activitiesに対応したらしい
こっちは試してないけど,C++とか書いてJavaやKotlinから呼び出すみたいな今までの開発をしなくても,KotlinでNativeになる時代が本当に来たのか~と思うと目から汁が出る

KotlinでDSL作って,HTMLとかJSとか全部Kotlinで書くみたいなプロジェクトが確かあったと思うけど,ホントにKotlinでなんでもかける時代が来るのかもしれない
Kotlin/Nativeが出たときに組み込みとかiOSアプリとかも作れるようにしたいって言ってたけど,もしかしたらKotlinでAndroidiOSの両方開発みたいなReactNativeとかXamarinみたいなのもできるようになるのか(胸熱)
まぁでもKotlinでJS書くの結構,頭切り替えなきゃいけないし,そこら辺の差をなくすのはまだまだ無理だろうな

こんなにいろんなことが出来るよって裾野広げて,開発チームは大丈夫なのかといらぬ心配をしてしまう
とにかくKotlinの今後にますます注目~

Mode Template for Processing 3.x を作った

前にMode Template for Processing 2.xを使ってProcessing 3.0.2で使えるMode作ったけど,なぜか動かなくなってたのでこの際だから3.x用作った
基本は2.xのまま借りてきている
少し直したのと,前はEclipseで作ってたけどIntelliJが好きだから,移行してIntelliJでつくった
ここからメンテナンスするかと言われればたぶんしない

github.com

String.prepend, String.append, String.minusの話

小ネタだけど,String関係で便利なやつ第2弾
解説すると,String.prepend(String)で前に追加,String.append(String)で後に追加
String - IntでInt文字数分削除

下の例だと,文字”STRING”にprepend("pre")で"preSTRING"
そのあとappend("app")で"preSTRINGapp"
最後にs - 1で最後の1文字を削除して"preSTRINGap"

operator fun String.minus(num: Int) = this.substring(0, this.length - num)

fun String.prepend(s: String) = this.javaClass.getDeclaredField("value").let {
    it.isAccessible = true
    it.set(this, s.toCharArray() + this.toCharArray())
    this
}

fun String.append(s: String) = this.javaClass.getDeclaredField("value").let {
    it.isAccessible = true
    it.set(this, this.toCharArray() + s.toCharArray())
    this
}

fun main(args: Array<String>) {
    val s = "STRING"
    s.prepend("pre").append("app")
    println(s - 1)  // ->  preSTRINGap
}

Stringに掛け算の演算子オーバーロードしたら捗った

最近Kotlinのoperatorとかinfix触っててよかった話をひとつ.

Stringで+を使うと結合になるわけだけど,なぜか*がない
なのでString.timesを作った
String * Int, String *= Intって感じ
これでいちいちfor回したりがなくなるので結構便利
デフォルトに組み込んでほしい^~

fun main(args: Array<String>) {
    operator fun String.times(num: Int): String {
        var s = ""
        for (i in 0..num) s += this
        return s
    }
    println("hell, " * 2 + "hell)//hell, hell, hell
}

ProcessingのTemplate Modeでビルドするときにスケッチ名とコードを取得する

続き: pvcresin.hatenablog.com

JavaModeを継承しているTemplateModeでhandleLaunchメソッドをOverrideする

メインのコードはhandleLaunchメソッドの中で,こんな感じ

String sketchName = sketch.getName();
System.out.println("handleLaunch: " + sketchName);
        
Editor editor = base.getActiveEditor();
String s = "";
for (int i = 0; i < editor.getLineCount(); i++){
    s += editor.getLineText(i);
}
System.out.println(s);

TemplateMode全体

package com.mydomain.mymode;

import java.io.File;
import processing.app.*;
import processing.app.ui.*;
import processing.mode.java.*;
import processing.mode.java.runner.Runner;

public class TemplateMode extends JavaMode {
    
    public TemplateMode(Base base, File folder) {
        super(base, folder);
    }

    /**
     * Return the pretty/printable/menu name for this mode. This is separate
     * from the single word name of the folder that contains this mode. It could
     * even have spaces, though that might result in sheer madness or total
     * mayhem.
     */
    @Override
    public String getTitle() {
        return "Template";
    }
    
    // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
   
    // Create a new editor associated with this mode.
//    @Override
//    public Editor createEditor(Base base, String path, EditorState state) {
//         return null;
//    }

    // Returns the default extension for this editor setup.
//    @Override
//    public String getDefaultExtension() {
//        return null;
//    }

    // Returns a String[] array of proper extensions.    
//    @Override
//    public String[] getExtensions() {
//        return null;
//    }

    // Get array of file/directory names that needn't be copied during "Save As".    
//    @Override
//    public String[] getIgnorable() {
//        return null;
//    }
    
    /**
     * Retrieve the ClassLoader for JavaMode. This is used by Compiler to load
     * ECJ classes. Thanks to Ben Fry.
     * @return the class loader from java mode
     */
//    @Override
//    public ClassLoader getClassLoader() {
//        for (Mode m : base.getModeList()) {
//            if (m.getClass() == JavaMode.class) {
//                JavaMode jMode = (JavaMode) m;
//                return jMode.getClassLoader();
//            }
//        }
//        return null;  // badness
//    }
    
    /** Handles the standard Java "Run" or "Present" */
    @Override
    public Runner handleLaunch(Sketch sketch, RunnerListener listener,
            final boolean present) throws SketchException {

        String sketchName = sketch.getName();
        System.out.println("handleLaunch: " + sketchName);
        
        Editor editor = base.getActiveEditor();
        String s = "";
        for (int i = 0; i < editor.getLineCount(); i++){
            s += editor.getLineText(i);
        }
        System.out.println(s);
        
      JavaBuild build = new JavaBuild(sketch);
      String appletClassName = build.build(true);
      
      if (appletClassName != null) {
        final Runner runtime = new Runner(build, listener);
        
        new Thread(new Runnable() {
          public void run() {   // these block until finished
            if (present) runtime.present(null);
            else runtime.launch(null);
          }
        }).start();
        
        return runtime;
      }
      return null;
    }    
  
}

KotlinのAnyを引数に持つ同名関数の優先順位について

fun(Any) < fun(String)
Anyが引数になってる関数よりStringとか限定された方が優先されるっぽい?

fun main(args: Array<String>) {
    p("hell")   // -> str
    p(10)       // -> int
    p(10.0)     // -> any
}

fun p(any: Any) = println("$any : any")

fun p(i: Int) = println("$i : int")

fun p(s: String) = println("$s : str")

Processing 3.0.2で動く自作ライブラリ(.jar)を作ろう

初めに

  • 自作クラスとか使いたい人向け
  • IntelliJ IDEA Community(free) 使用
  • Java ->.jar ファイル(ライブラリ本体)を吐き出す

プロジェクト作成

  • Processing が3.0.2なので,JDKは1.8を使用

  • IDEA: File>New>ProjectでtestLibを作成

  • その中のsrcにtestPackageを作成
  • またその中にJavaClass.javaを作成

今回はPApppletを扱えるライブラリにしたいので, IDEA: File>Project Structure>Librariesで+を押してcore.jar(Processing3.0.2>core>library)を入れる

Project表示ではこんな感じ

f:id:pvcresin:20160317220251p:plain

JavaClass.javaを書いてみる

最初にProcessing側からPAppletをもらってきて,bgというメソッドが呼ばれたらPAppletのバックグラウンドの色を変えるというだけのクラス.

package testPackage;

import processing.core.*;

public class JavaClass {
    PApplet pa;

    public JavaClass(PApplet pa) {
        this.pa = pa;
    }
    public void bg(int color){
        pa.background(color);
    }
    public static void main(String[] args) {

    }
}

.jar 作り

  1. IDEA: File>Project Structure>Artifacts
  2. +押す>JAR >From modules with dependencies
  3. Main ClassにJavaClassを選択する main()がないとかクラスに不備があると表示されないことがある
  4. JavaClass.javaのエディット画面に戻り,IDEA: Build>Build Artifactsからビルド
  5. testLib>out>artifacts>testLib_jarファイルのなかにtestLib.jarができているはず

f:id:pvcresin:20160317222510p:plain

Processingで使用

できた.jarを自分のスケッチにドラッグ&ドロップして下のコードをProcessingで書くだけ

import testPackage.JavaClass;

JavaClass j = new JavaClass(this);

void setup() {
  size(300, 300);
  background(255);
}
void draw() {
}
void mousePressed() {
  j.bg(color(255, 0, 0));
}

ライブラリ作りの参考:

Processingのライブラリを作る - gutugutu3030

IntelliJ IDEAでの .jarの作り方の参考:

qiita.com