Topik ini membahas struktur berkas proyek F# dan pengelolaannya lewat command line .NET, mulai dari anatomi berkas fsproj, pembuatan proyek dengan dotnet new, sampai solusi yang merangkai beberapa proyek sekaligus. Contohnya berupa satu solusi kecil berisi proyek konsol dan proyek pustaka untuk rekap nilai ujian. Setelah topik ini dibaca, pembuatan proyek, penautan antarproyek, serta build dan run dapat dilakukan sepenuhnya dari terminal.
Anatomi berkas fsproj#
Setiap proyek F# diatur oleh satu berkas fsproj berformat XML. Berkas itu mendeklarasikan SDK yang digunakan, properti build, dan daftar berkas kode yang dikompilasi. Proyek baru dibuat dengan perintah dotnet new, dan templat console menghasilkan aplikasi yang dapat dieksekusi langsung dari terminal.
# membuat proyek konsol F# bernama StatistikNilai
dotnet new console -lang F# -o StatistikNilaiPerintah di atas membuat folder StatistikNilai yang berisi dua berkas, yaitu StatistikNilai.fsproj dan Program.fs. Nama proyeknya mengikuti nama folder pada opsi -o. Keluaran perintah ini memuat konfirmasi templat beserta durasi pemulihan paket yang berubah pada setiap eksekusi, sehingga keluarannya tidak ditempelkan pada topik ini. Isi berkas fsproj yang dihasilkan templat adalah sebagai berikut.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Compile Include="Program.fs" />
</ItemGroup>
</Project>Atribut Sdk pada elemen Project menunjuk ke Microsoft.NET.Sdk, yaitu kumpulan target build yang menyediakan seluruh langkah kompilasi dan pemulihan paket. Elemen PropertyGroup menampung properti build proyek. Properti OutputType bernilai Exe karena proyek ini dibangun menjadi aplikasi yang dapat dieksekusi, sedangkan TargetFramework bernilai net10.0 yang memilih .NET 10 sebagai platform target. Elemen ItemGroup di bagian bawah mendaftarkan Program.fs sebagai satu-satunya berkas kode yang dikompilasi. Templat mengisi berkas tersebut dengan satu pemanggilan printfn yang mencetak sapaan, sehingga proyek baru dapat langsung dijalankan sebelum satu baris kode pun ditulis.
Proyek pustaka untuk logika domain#
Logika yang akan diuji pada modul ini sebaiknya terpisah dari aplikasi pemanggilnya, dan pemisahan itu dilakukan dengan proyek pustaka kelas (class library). Proyek pustaka dibuat dengan templat classlib yang prosesnya sama persis dengan templat konsol.
# membuat proyek pustaka kelas F# bernama IntiNilai
dotnet new classlib -lang F# -o IntiNilai<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>
<ItemGroup>
<Compile Include="Library.fs" />
</ItemGroup>
</Project>Berkas fsproj pustaka berbeda dari versi konsol pada dua hal. Properti OutputType tidak ada karena tanpa elemen itu proyek dibangun sebagai library, yaitu rakitan (assembly) yang digunakan proyek lain dan tidak memiliki titik masuk. Properti GenerateDocumentationFile bernilai true sehingga komentar dokumentasi pada kode pustaka dikumpulkan menjadi berkas XML. Berkas Library.fs milik templat diganti dengan modul statistik sederhana berikut.
// tidak-dijalankan: berkas proyek ini dieksekusi melalui blok bash berikutnya
namespace IntiNilai
// fungsi statistik dasar untuk rekap nilai ujian
module Perhitungan =
let rataRata (nilai: int list) : float =
List.averageBy float nilai
let maksimum (nilai: int list) : int =
List.max nilai
let minimum (nilai: int list) : int =
List.min nilai# mengisi berkas Library.fs pustaka dari berkas yang ditampilkan di atas
cp Library.fs IntiNilai/Library.fsKetiga fungsi pada modul Perhitungan murni, yaitu menerima daftar nilai dan mengembalikan hasil perhitungan tanpa efek samping. Bentuk seperti ini yang kelak diuji dengan Expecto dan FsCheck. Penempatan fungsi di proyek pustaka sejak awal membuat pengujian tidak perlu menyentuh kode antarmuka.
Solusi multi proyek#
Dua proyek yang terpisah akan sulit dikelola satu per satu karena setiap perintah build harus menyebut masing-masing proyek. Solusi (solution) memecahkan hal itu dengan merangkai beberapa proyek dalam satu berkas, sehingga build dan pengujian dapat menyasar semuanya sekaligus. Berkas solusi dibuat dengan dotnet new sln, lalu proyek didaftarkan satu per satu dengan dotnet sln add.
# membuat berkas solusi untuk merangkai kedua proyek
dotnet new sln -n StatistikNilai
# mendaftarkan kedua proyek ke dalam solusi
dotnet sln add StatistikNilai/StatistikNilai.fsproj IntiNilai/IntiNilai.fsprojThe template "Solution File" was created successfully.
Project `StatistikNilai/StatistikNilai.fsproj` added to the solution.
Project `IntiNilai/IntiNilai.fsproj` added to the solution.Kedua perintah di atas menghasilkan berkas StatistikNilai.slnx di folder kerja. Isinya berupa daftar proyek yang telah didaftarkan. Setiap proyek muncul sebagai elemen Project dengan atribut Path yang menunjuk ke berkas fsproj-nya.
<Solution>
<Project Path="IntiNilai/IntiNilai.fsproj" />
<Project Path="StatistikNilai/StatistikNilai.fsproj" />
</Solution>Referensi antar proyek#
Proyek konsol perlu memanggil fungsi dari IntiNilai, dan hubungan itu dinyatakan lewat referensi proyek (project reference). Perintah dotnet add reference menambahkan referensi tersebut pada berkas fsproj proyek pemakai.
# menghubungkan proyek konsol ke proyek pustaka
dotnet add StatistikNilai reference IntiNilai/IntiNilai.fsprojReference `..\IntiNilai\IntiNilai.fsproj` added to the project. <ItemGroup>
<ProjectReference Include="..\IntiNilai\IntiNilai.fsproj" />
</ItemGroup>Elemen ProjectReference membuat StatistikNilai bergantung pada IntiNilai. Saat proyek konsol dibangun, proyek pustaka dibangun lebih dahulu, kemudian hasil kompilasinya dirujuk oleh proyek pemakai. Pesan perintah dan isi fsproj keduanya menuliskan jalur dengan pemisah ala Windows pada semua sistem operasi, bentuk yang memang digunakan MSBuild secara internal. Arah referensinya satu arah, yaitu dari konsol ke pustaka, sehingga pustaka tidak mengetahui aplikasi pemakainya dan tetap dapat digunakan proyek lain.
Build dan run dari CLI#
Berkas Program.fs milik templat kini diganti dengan program yang menghitung rekap nilai ujian lewat fungsi pustaka.
// tidak-dijalankan: berkas proyek ini dieksekusi melalui blok bash berikutnya
// rekap nilai ujian memanggil fungsi dari proyek pustaka IntiNilai
open IntiNilai
let nilai = [ 80; 45; 75; 90; 60 ]
printfn "Rata-rata : %.1f" (Perhitungan.rataRata nilai)
printfn "Nilai maksimum : %d" (Perhitungan.maksimum nilai)
printfn "Nilai minimum : %d" (Perhitungan.minimum nilai)# mengisi berkas Program.fs proyek konsol dari berkas yang ditampilkan di atas
cp Program.fs StatistikNilai/Program.fs
# membangun seluruh proyek yang terdaftar pada solusi
dotnet build StatistikNilai.slnxPerintah dotnet build memulihkan paket bila diperlukan, kemudian mengompilasi kedua proyek mengikuti urutan referensinya. Keluarannya memuat jalur absolut folder build dan durasi yang berubah pada setiap eksekusi, sehingga keluarannya tidak ditempelkan pada topik ini. Build yang berhasil diakhiri pesan Build succeeded dengan hitungan warning dan error nol.
# menjalankan proyek konsol; program memanggil fungsi dari pustaka
dotnet run --project StatistikNilaiRata-rata : 70.0
Nilai maksimum : 90
Nilai minimum : 45Rata-rata 70.0 berasal dari jumlah 350 yang dibagi lima nilai, sedangkan nilai maksimum dan minimum langsung dibaca dari daftar. Opsi --project menunjuk proyek yang dieksekusi, sehingga perintah dapat dijalankan dari folder solusi tanpa masuk ke folder proyek terlebih dahulu. Eksekusi berikutnya jauh lebih cepat karena hanya berkas yang berubah yang dikompilasi ulang.
Kesalahan umum#
- Berkas
.fsbaru tidak ikut dikompilasi. Berbeda dari SDK C# yang menyertakan seluruh berkas.csdi folder secara otomatis, SDK F# hanya mengompilasi berkas yang terdaftar pada elemenCompile Includedi fsproj. Berkas kode baru wajib didaftarkan pada berkas tersebut, dan perubahannya baru terlihat setelah proyek dibangun ulang. - Urutan berkas pada
Compile Includeterbalik. F# mengompilasi berkas satu per satu mengikuti urutan daftarnya, sehingga berkas yang menggunakan tipe atau modul dari berkas lain harus dituliskan setelah berkas pemiliknya. Apabila urutannya terbalik, compiler melaporkan error pengenal tidak dikenal, dan perbaikannya dengan menaikkan berkas pemilik tipe ke posisi yang lebih atas.
Ringkasan#
- Berkas fsproj mendeklarasikan SDK,
TargetFramework net10.0,OutputType, dan daftar berkas kode yang dikompilasi sesuai urutannya. dotnet newmembuat proyek, sedangkandotnet new slndandotnet sln addmerangkai beberapa proyek ke dalam satu solusi.slnx.dotnet add referencemenuliskanProjectReferenceyang menyatakan ketergantungan proyek konsol pada proyek pustaka.dotnet buildmengompilasi seluruh proyek dalam solusi, sedangkandotnet run --projectmengeksekusi satu proyek dari folder solusi.
Referensi#
- dotnet new — Microsoft Learn — dokumentasi resmi pembuatan proyek dari templat, termasuk templat console dan classlib F#.
- dotnet sln — Microsoft Learn — dokumentasi resmi pembuatan solusi dan pendaftaran proyek beserta format solusinya.
- dotnet add reference — Microsoft Learn — dokumentasi resmi penambahan referensi antar proyek pada berkas fsproj.
- dotnet build — Microsoft Learn — dokumentasi resmi build proyek dan solusi beserta pemulihan paket implisitnya.
- dotnet run — Microsoft Learn — dokumentasi resmi menjalankan proyek dari sumber tanpa perintah build terpisah.