1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

juliaの環境を構築してみた

1
Last updated at Posted at 2026-09-13

juliaってなにそれ?おいしいの?

juliaとは、科学技術計算やデータ解析に向いた高水準言語のこと。
C言語並みの速さとPythonのような使いやすさを目指して開発された言語です。
LLVM JITのおかげで超速い!!
pycall.jlというのでpythonの命令をを呼び出せるらしい。詳しくはわからぬ・・・

さあ環境を構築してみよう!!

1.本体をインストールする

コマンドでインストールしたほうが早いです。
インストール当時、イーサネットがおかしくてgithubにつながらずインストールにてこずりましたが、
LANを抜き差ししたらいけました。ネットワークの設定が再構築されたのかな?よくわかんない:wink:

コマンド:

windowsの場合

winget install --name Julia --id 9NJNWW8PVKMN -e -s msstore

macやlinuxの場合

curl -fsSL https://install.julialang.org | sh

これだと最新版が入るのでLTSがいい人は入れた後、

juliaup add lts

をして、

juliaup default lts

をするとLTSが入ります
※筆者はLTSを入れました。

2.エディタを準備する

エディタがなくては話になりません。
私はjetbrains IDEを愛用しているのでPyCharmを使いましたが、VSCodeがいい人はそれでもいいです。
※ここではjetbrains IDEで環境を構築します。VSCodeは拡張機能を入れるだけです。(多分・・・)

Fatouを入れる

rust製の高速リンターです。これがないとインテリセンスが出なくて最悪環境になります。

cargoから入れる場合:

cargo install fatou

uvから入れる場合

uv tool install fatou

pipでも大体一緒です。詳しくは調べてください(丸投げ)

npmから入れる場合

npm install -g fatou-cli

自分はnpmに詳しくないのでこれであってるかわかりません

これでfatouが入ります。

3.リンターをエディタと連携する

リンターとエディタを連携します。これでインテリセンスが出るようになります。

プラグインの画面を開いて、検索ボックスにLSP4IJと入力します。

スクリーンショット 2026-09-13 164149.png
これをインストールします。
次に、設定から、
言語&フレームワーク→Launguage Serversの画面で、
Serverのcommand欄に
fatou lsp
mappingsのfile name patternsの画面で+を押して、
file name patternsのセルに、
*.jl を、
launguage idのセルに、
julia
と入力します

image.png
そして[適用]ボタンを押して、[OK]を押します。
これで、fatouと連携できました!!

4.外部ツールとして実行ボタンを作る

実行ボタンを作ります。作り方は簡単で、
設定から、
ツール→外部ツール で、
+ボタンを押して新規作成します。

image.png
名前をjulia run
プログラムをjulia
引数を--project=. "\$FilePath$" に、
作業ディレクトリを\$ProjectFileDir\$
にして[OK]→[適用]を押します。
これで外部ツールとして登録できます。
呼び出したいときは、
テキストエディタ上で右クリック→外部ツール→julia runでできます。
ボタンとしてどこかに置くこともできるみたいです。

5.プロジェクト新規作成画面を作る

これは任意です。自分はC#が使えるのでAvalonia UIで作りました。
一応コードを貼っときます。

App.axaml
<Application xmlns="https://github.com/avaloniaui"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             x:Class="NewjuliaProject.App"
             RequestedThemeVariant="Dark"> <!-- アプリ全体をダークモードに -->

    <Application.Styles>
        <FluentTheme />
    </Application.Styles>

    <Application.Resources>
        <!-- アプリ全体の角丸を一括定義(これでWindow内でも有効になります) -->
        <CornerRadius x:Key="ControlCornerRadius">5</CornerRadius>
        <CornerRadius x:Key="OverlayCornerRadius">10</CornerRadius>
        <CornerRadius x:Key="WindowCornerRadius">12</CornerRadius>
    </Application.Resources>
</Application>
MainWindow.axaml.cs
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Platform.Storage;
using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;

namespace NewjuliaProject
{
    public partial class MainWindow : Window
    {
        // julia実行がハングした場合の安全装置(必要に応じて調整)
        private static readonly TimeSpan ProcessTimeout = TimeSpan.FromMinutes(3);

        // Windows/一般的なファイルシステムで問題になりやすい文字を禁止
        private static readonly Regex InvalidProjectNamePattern =
            new Regex("[\\\\/:*?\"<>|\\x00-\\x1F]", RegexOptions.Compiled);

        public MainWindow()
        {
            InitializeComponent();
        }

        // ラジオボタンの挙動を再現する処理
        private void OnProjectTypeChanged(object sender, RoutedEventArgs e)
        {
            if (object.Equals(sender, JuliaToggle))
            {
                JuliaToggle.IsChecked = true;
                PlutoToggle.IsChecked = false;
            }
            else if (object.Equals(sender, PlutoToggle))
            {
                JuliaToggle.IsChecked = false;
                PlutoToggle.IsChecked = true;
            }
        }

        // フォルダ選択ボタンの処理
        private async void Button_OnClick(object? sender, RoutedEventArgs e)
        {
            try
            {
                var options = new FolderPickerOpenOptions
                {
                    Title = "プロジェクトの保存先フォルダを選択",
                    AllowMultiple = false
                };

                var result = await StorageProvider.OpenFolderPickerAsync(options);

                if (result.Count > 0)
                {
                    string folderPath = result[0].Path.LocalPath;
                    PathTextBox.Text = folderPath;
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"フォルダ選択中にエラーが発生しました: {ex.Message}");
                await ShowErrorAsync("フォルダの選択に失敗しました。", ex.Message);
            }
        }

        // 新規作成ボタンが押されたときの処理
        private async void CreateButton_OnClick(object? sender, RoutedEventArgs e)
        {
            string projectName = ProjectNameTextBox.Text?.Trim() ?? "";
            string baseQuantityPath = PathTextBox.Text?.Trim() ?? "";

            // --- 入力チェック ---
            if (string.IsNullOrEmpty(projectName) || string.IsNullOrEmpty(baseQuantityPath))
            {
                Debug.WriteLine("プロジェクト名またはパスが空です。");
                await ShowErrorAsync("入力エラー", "プロジェクト名と保存先フォルダを入力してください。");
                return;
            }

            if (InvalidProjectNamePattern.IsMatch(projectName) ||
                projectName.Contains("..") ||
                projectName == "." )
            {
                await ShowErrorAsync("入力エラー",
                    "プロジェクト名に使用できない文字(\\ / : * ? \" < > | など)または \"..\" が含まれています。");
                return;
            }

            // 二重クリック防止
            SetBusy(true);

            try
            {
                if (!Directory.Exists(baseQuantityPath))
                {
                    Directory.CreateDirectory(baseQuantityPath);
                }

                bool isJulia = JuliaToggle.IsChecked ?? false;

                if (isJulia)
                {
                    await CreateJuliaProjectAsync(projectName, baseQuantityPath);
                }
                else
                {
                    await CreatePlutoProjectAsync(projectName, baseQuantityPath);
                }

                Debug.WriteLine("プロジェクトの初期化が正常に完了しました!");
                this.Close();
            }
            catch (OperationCanceledException)
            {
                Debug.WriteLine("Juliaプロセスがタイムアウトしました。");
                await ShowErrorAsync("タイムアウト",
                    "Juliaの実行がタイムアウトしました。Juliaがインストールされていて、PATHが通っているか確認してください。");
            }
            catch (JuliaExecutionException jex)
            {
                Debug.WriteLine($"Julia実行エラー: {jex.Message}");
                await ShowErrorAsync("Juliaの実行に失敗しました", jex.Message);
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"初期化中にエラーが発生しました: {ex.Message}");
                await ShowErrorAsync("初期化エラー", ex.Message);
            }
            finally
            {
                SetBusy(false);
            }
        }

        // 🔷 Julia標準プロジェクトの初期化
        private async Task CreateJuliaProjectAsync(string projectName, string baseQuantityPath)
        {
            Debug.WriteLine("Juliaプロジェクトの初期化を開始します...");

            string targetPath = Path.Combine(baseQuantityPath, projectName);
            if (Directory.Exists(targetPath))
            {
                throw new JuliaExecutionException($"フォルダ \"{projectName}\" は既に存在します。別の名前を指定してください。");
            }

            var startInfo = new ProcessStartInfo
            {
                FileName = "julia",
                WorkingDirectory = baseQuantityPath,
                RedirectStandardOutput = true,
                RedirectStandardError = true,
                UseShellExecute = false,
                CreateNoWindow = true,
                StandardOutputEncoding = Encoding.UTF8,
                StandardErrorEncoding = Encoding.UTF8,
            };

            // 文字列連結ではなく ArgumentList を使い、引数インジェクションを防止
            startInfo.ArgumentList.Add("-e");
            startInfo.ArgumentList.Add($"using Pkg; Pkg.generate(\"{projectName}\")");

            Process? process;
            try
            {
                process = Process.Start(startInfo);
            }
            catch (Exception ex) when (ex is System.ComponentModel.Win32Exception || ex is FileNotFoundException)
            {
                // "julia" コマンドが見つからない場合など
                throw new JuliaExecutionException(
                    "juliaコマンドを実行できませんでした。Juliaがインストールされ、PATHが通っているか確認してください。", ex);
            }

            if (process == null)
            {
                throw new JuliaExecutionException("juliaプロセスを開始できませんでした。");
            }

            using (process)
            {
                // 標準出力・標準エラーの読み取りは WaitForExitAsync と並行して開始する
                // (先に Wait してから読むとパイプが詰まってデッドロックする可能性があるため)
                Task<string> outputTask = process.StandardOutput.ReadToEndAsync();
                Task<string> errorTask = process.StandardError.ReadToEndAsync();

                using var cts = new CancellationTokenSource(ProcessTimeout);
                try
                {
                    await process.WaitForExitAsync(cts.Token);
                }
                catch (OperationCanceledException)
                {
                    TryKill(process);
                    throw;
                }

                string output = await outputTask;
                string error = await errorTask;

                Debug.WriteLine($"Julia出力: {output}");
                if (!string.IsNullOrEmpty(error)) Debug.WriteLine($"Juliaエラー: {error}");

                if (process.ExitCode != 0)
                {
                    string message = string.IsNullOrWhiteSpace(error)
                        ? $"Juliaプロセスが異常終了しました(終了コード: {process.ExitCode})。"
                        : error;
                    throw new JuliaExecutionException(message);
                }
            }
        }

        // 🔸 Plutoプロジェクトの初期化
        private async Task CreatePlutoProjectAsync(string projectName, string baseQuantityPath)
        {
            Debug.WriteLine("Plutoプロジェクトの初期化を開始します...");

            string plutoFolderPath = Path.Combine(baseQuantityPath, projectName);
            if (Directory.Exists(plutoFolderPath))
            {
                throw new JuliaExecutionException($"フォルダ \"{projectName}\" は既に存在します。別の名前を指定してください。");
            }

            Directory.CreateDirectory(plutoFolderPath);

            string notebookPath = Path.Combine(plutoFolderPath, "notebook.jl");

            // 最低限のPluto.jlノートブック形式(セルIDとフッターを含む)
            const string cellId = "00000000-0000-0000-0000-000000000001";
            string plutoContent =
                "### A Pluto.jl notebook ###\n" +
                "# v0.19.0\n\n" +
                "using Markdown\n" +
                "using InteractiveUtils\n\n" +
                $"# ╔═╡ {cellId}\n" +
                "println(\"Hello Pluto!\")\n\n" +
                "# ╔═╡ Cell order:\n" +
                $"# ╠═{cellId}\n";

            await File.WriteAllTextAsync(notebookPath, plutoContent, Encoding.UTF8);
            Debug.WriteLine($"Plutoノートブックを作成しました: {notebookPath}");
        }

        private void SetBusy(bool isBusy)
        {
            // ボタンの多重クリックを防止
            CreateButton.IsEnabled = !isBusy;
            // 名称は実際のXAMLに合わせて調整してください(例: CreateButton)
        }

        private static void TryKill(Process process)
        {
            try
            {
                if (!process.HasExited) process.Kill(entireProcessTree: true);
            }
            catch
            {
                // プロセス終了時の例外は無視して良い
            }
        }

        // シンプルなエラーダイアログ表示(外部ライブラリ非依存)
        private async Task ShowErrorAsync(string title, string message)
        {
            var dialog = new Window
            {
                Title = title,
                Width = 400,
                SizeToContent = SizeToContent.Height,
                CanResize = false,
                WindowStartupLocation = WindowStartupLocation.CenterOwner,
            };

            var okButton = new Button { Content = "OK", HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Center, Margin = new Avalonia.Thickness(0, 10, 0, 0) };
            okButton.Click += (_, _) => dialog.Close();

            dialog.Content = new StackPanel
            {
                Margin = new Avalonia.Thickness(20),
                Children =
                {
                    new TextBlock { Text = message, TextWrapping = Avalonia.Media.TextWrapping.Wrap },
                    okButton
                }
            };

            await dialog.ShowDialog(this);
        }

        // Julia実行に関する独自例外
        private sealed class JuliaExecutionException : Exception
        {
            public JuliaExecutionException(string message) : base(message) { }
            public JuliaExecutionException(string message, Exception inner) : base(message, inner) { }
        }
    }
}
MainWindow.axaml
<Window xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
        x:Class="NewjuliaProject.MainWindow"
        Title="NewjuliaProject"
        Background="Transparent"
        TransparencyLevelHint="AcrylicBlur"
        RequestedThemeVariant="Dark">
    
    <!-- 画面全体に黒ベースのすりガラス(アクリル)背景を敷く -->
    <Panel>
        <ExperimentalAcrylicBorder IsHitTestVisible="False">
            <ExperimentalAcrylicBorder.Material>
                <ExperimentalAcrylicMaterial
                    BackgroundSource="Digger"
                    TintColor="Black"
                    TintOpacity="0.8"
                    MaterialOpacity="0.99" />
            </ExperimentalAcrylicBorder.Material>
        </ExperimentalAcrylicBorder>
        
        <!-- 全体をGridにして、左右のエリアに分割 -->
        <Grid ColumnDefinitions="Auto, *" Margin="20">
            
            <!-- 左側のエリア(トグルボタンを配置) -->
            <StackPanel Grid.Column="0" Orientation="Vertical" Spacing="10" Width="180" Margin="0,0,20,0">
                <TextBlock Text="プロジェクトの種類" FontWeight="Bold"/>
    
                <ToggleButton Name="JuliaToggle" 
                              Content="juliaプロジェクト" 
                              IsChecked="True"
                              Click="OnProjectTypeChanged"
                              HorizontalAlignment="Stretch" 
                              HorizontalContentAlignment="Center"/>
                 
                <ToggleButton Name="PlutoToggle" 
                              Content="Plutoプロジェクト" 
                              Click="OnProjectTypeChanged"
                              HorizontalAlignment="Stretch" 
                              HorizontalContentAlignment="Center"/>
            </StackPanel>

            <!-- 右側のエリア -->
            <Grid Grid.Column="1" RowDefinitions="*, Auto">
                
                <!-- 上段:入力フォーム -->
                <StackPanel Grid.Row="0" Orientation="Vertical" Spacing="10">
                    <TextBlock Text="プロジェクト名" FontWeight="Bold"/>
                    <TextBox Name="ProjectNameTextBox" PlaceholderText="プロジェクト名" HorizontalAlignment="Stretch"/>

                    <TextBlock Text="パス" FontWeight="Bold"/>
                    <TextBox Name="PathTextBox" PlaceholderText="パス" HorizontalAlignment="Stretch">
    
                        <TextBox.InnerRightContent>
                            <Button Background="Transparent" 
                                    BorderThickness="0" 
                                    Padding="6,4"
                                    VerticalAlignment="Center"
                                    Click="Button_OnClick">
                                <Path Data="M3 5C3 3.89543 3.89543 3 5 3H9.41421C9.94466 3 10.4534 3.21071 10.8284 3.58579L12.2426 5H19C20.1046 5 21 5.89543 21 7V17C21 18.1046 20.1046 19 19 19H5C3.89543 19 3 18.1046 3 17V5ZM5 5V17H19V7H11.5858L10.1716 5.58579C9.79652 5.21071 9.28779 5 8.75736 5H5Z" 
                                      Fill="White" 
                                      Width="16" 
                                      Height="16" 
                                      Stretch="Uniform" />
                            </Button>
                        </TextBox.InnerRightContent>
    
                    </TextBox>

                </StackPanel>
                
                <!-- 下段:新規作成ボタン -->
                <!-- Name="CreateButton" を追加:処理中に IsEnabled=false にして二重クリックを防止するため -->
                <Button Name="CreateButton"
                        Grid.Row="1" 
                        Content="新規作成" 
                        Background="DodgerBlue" 
                        Padding="15,8" 
                        HorizontalAlignment="Right" 
                        VerticalAlignment="Bottom"
                        Click="CreateButton_OnClick"/>
            </Grid>
            
        </Grid>
    </Panel>
</Window>

画面

image.png

終わりに

今回はjuliaの環境構築をしてみました。juliaは汎用的な言語なので、この言語を使えば将来役に立つはずです。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?