Aqoole_Hateenaの技術日記

vulkan+raytraceで色々描いてます

共有ライブラリの作成方法@vscode in Linux

Linux + vscodeの環境での共有ライブラリ(実行時ライブラリ、ランタイムライブラリ)の作成方法について調べた。

結論

簡単に結論から
1. 共有ライブラリの作成

clang++(g++) -fPIC -shared -o <libshared.so.1.0.0> xxx.cpp yyy.cpp ...   

2. シンボリックリンクをはる

ln -nfs libshared.so.1.0.0 libshared.so

3. main.cppのビルドにshared libを利用

clang++ -o main.exe main.cpp -lshared ...

4. launch.jsonのLD_LIBRARY_PATH修正

"LD_LIBRARY_PATH" : "/usr/lib/x86_64-linux-gnu:/home/Sources/myprojectpath"

1. 共有ライブラリの作成

静的ライブラリ(x.a)と共有ライブラリ(x.so)の違いや作成コマンドは次のリンク先に書かれているが、簡単に言えばコンパイルするプログラムのサイズに違いが出てくる。
技術レポート「Linuxのライブラリ開発」|ソフテックだより|株式会社ソフテック
実際に比べてみた結果がこちら

・共有ライブラリなし

-rwxrwxr-x 1 user user 9.4M 10月 15 22:29 main.exe

=> 9.4MB

・共有ライブラリあり

lrwxrwxrwx 1 user user   20 10月 15 22:18 libshared.so -> libshared.so.1.0.0
-rwxrwxr-x 1 user user 9.3M 10月 15 22:18 libshared.so.1.0.0
-rwxrwxr-x 1 user user 1.9M 10月 15 22:18 main.exe

=> 合計11.2MB

単純に合計値を比べた場合、main.exe + 共有ライブラリに分けた方が容量は大きくなるようだが、共有ライブラリは他のプログラムでも流用できることを考えると、こちらの方が便利かも。
もちろん、ライブラリ部分を切り出せばmain.exeの容量は小さくなる。

vscodeに記述する場合、tasks.jsonにライブラリ作成コマンドを記述する。

{
    // See https://go.microsoft.com/fwlink/?LinkId=733558
    // for the documentation about the tasks.json format
    "version": "2.0.0",
  "tasks": [
    {
        "label": "shared_lib",
        "type": "shell",
        "command": "clang++",
        "args": [
            "-std=c++17",
            "-fPIC",
            "-shared",
            "-g",
            "-o",
            "libshared.so.1.0.0",
            "a.cpp",
            "b.cpp",
            "-lvulkan",
            "-lvulkan_radeon",
            "-lvulkan_intel",
            "-march=native",
        ],
        "group": {
            "kind": "build",
            "isDefault": true
        },
        "problemMatcher": [
            "$eslint-compact"
        ]
    },
    {
        "label": "link",
        "type": "shell",
        "command": "ln",
        "args": [
            "-nfs",
            "libshared.so.1.0.0",
            "libshared.so",
        ],
        "dependsOn" : [
            "shared_lib"
        ]
    },
    {
        "label": "echo",
        "type": "shell",
        "command": "clang++",
        "args": [
            "-std=c++17",
            "-g",
            "-o",
            "${fileBasenameNoExtension}.exe",
            "${file}",
    "-L/home/Sources/myprojectpath",
            "-lshared",
            "-lvulkan",
            "-lvulkan_radeon",
            "-lvulkan_intel",
            "-march=native",
        ],
        "group": {
            "kind": "build",
            "isDefault": true
        },
        "dependsOn" : [
            "link"
        ],
        "problemMatcher": [
            "$eslint-compact"
        ]
    }
]
}

vscodeのtasks.jsonには複数のtaskを記述することが可能で、順序はdependsOnで制御することができる。
VSCodeでタスク実行時に複数コマンド実行 - Qiita

2. シンボリックリンクをはる

前述のリンク先でもあったように、共有ライブラリには命名規則があり、soファイルはシンボリックリンクで作成しておき、実態は別のところにあるという記述の仕方を行う。
メリットとしては単純にリンク先を変えることで古いバージョンを指すようにできたり、また最新版を指すようにしてプログラムを再コンパイルすることなくアップデートすることができる。
http://archive.linux.or.jp/JF/JFdocs/Program-Library-HOWTO/shared-libraries.html
アーカイブリナックの記事にはldconfigコマンドでシステム全体に共有ライブラリを認識させる方法も書かれているが、ここでは開発用にローカルに認識できれば良いとしてこの作業は行っていない。
ldconfigについては次の記事など、探せば色々見つかるよう。
https://wa3.i-3-i.info/word13812.html

3 main.cppのビルドにshared libを利用

単純に-lオプションでリンクする。

4 launch.jsonのLD_LIBRARY_PATH修正

プログラム実行時にライブラリを探せる必要があるので、launch.jsonにLD_LIBRARY_PATHに作成した共有ライブラリのパスを検索できるように追加する。
以下の記事に
"Multiple directories can be listed, separated by a colon (:)"
と書かれているので、:で分けて記述する。
LD_LIBRARY_PATH – or: How to get yourself into trouble!

私はCodeLLDBというextensionを入れているので、以下のような書き方になっている。

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [

    {
        "name": "Launch",
        "type" : "lldb",
        "request": "launch",
        "program": "${workspaceFolder}/${fileBasenameNoExtension}.exe",
        "args": [],
        "stopOnEntry": false,
        "cwd": "${workspaceFolder}",
        "env": 
        {
            "LD_LIBRARY_PATH" : "/usr/lib/x86_64-linux-gnu:/home/Sources/myprojectpath",
            "VK_LAYER_PATH" : "/usr/share/vulkan/explicit_layer.d"
        },
        "terminal": "console",
    }
]
}

未確認だが、通常のenvironmentには以下のように記述すると思われる。

        "environment": 
        [
            {
                "name" : "LD_LIBRARY_PATH",
                "value" : "/usr/lib/x86_64-linux-gnu:/home/Sources/myprojectpath"
            },
            {
                "name" : "VK_LAYER_PATH",
                "value" : "/usr/share/vulkan/explicit_layer.d"
            }
        ],

最後に

普段はVulkan + Ray Tracingでグラフィクス周りを記事で書いていますが、今回はすこし視野を広げて開発環境をよくする意味でvscode in Linuxの環境での共有ライブラリの作成などについて調べたことを記事にしてみました。
Linuxで開発環境を作っている人自体が少数派のはずなので誰の助けになるかは不明ですが、誰かの助けになることを期待しています。