Genellikle karmaşık olan WORKSPACE
'dan Bzlmod'a geçiş sürecini basitleştirmek için taşıma komut dosyasını kullanmanız önemle tavsiye edilir. Bu yardımcı araç, harici bağımlılık yönetim sisteminizi taşıma işleminde yer alan birçok adımı otomatikleştirir.
Not: Yapay zeka destekli Bzlmod taşıma özelliğini denemek istiyorsanız Bzlmod Taşıma Aracısı Kurulumu başlıklı makaleyi inceleyin.
Temel işlevler
Komut dosyasının temel işlevleri şunlardır:
- Bağımlılık bilgilerini toplama: Belirtilen derleme hedefleri tarafından kullanılan harici depoları belirlemek için projenizin
WORKSPACE
dosyasını analiz etme, bu bilgileri içeren çözümlenmiş bir bağımlılık dosyası oluşturmak için Bazel'in experimental_repository_resolved_file işaretini kullanma. - Doğrudan bağımlılıkları belirleme: Belirtilen hedefler için hangi depoların doğrudan bağımlılık olduğunu belirlemek üzere
bazel query
kullanılır. - Bzlmod'a geçiş: İlgili
WORKSPACE
bağımlılıklarını Bzlmod'daki eşdeğerlerine çevirme. Bu işlem iki adımdan oluşur:- Belirlenen tüm doğrudan bağımlılıkları
MODULE.bazel
dosyasına ekleyin. - Bzlmod etkinleştirilmişken belirtilen hedefleri oluşturun, ardından tanınabilir hataları yinelemeli olarak belirleyip düzeltin. İlk adımda bazı bağımlılıklar eksik olabileceğinden bu adım gereklidir.
- Belirlenen tüm doğrudan bağımlılıkları
- Taşıma raporu oluşturma: Taşıma sürecini belgeleyen bir
migration_info.md
dosyası oluşturma. Bu raporda, doğrudan bağımlılıkların listesi, oluşturulan Bzlmod beyanları ve geçişi tamamlamak için gerekebilecek tüm manuel adımlar yer alır.
Taşıma aracı şunları destekler:
- Bazel Merkezi Kayıt Defteri'nde bulunan bağımlılıklar
- Kullanıcı tanımlı özel depo kuralları
- Paket yöneticisi bağımlılıkları
- Maven
- Go
- Python
Önemli Notlar:
- Taşıma aracı, en iyi girişim temel alınarak sunulan bir yardımcı programdır. Önerilerinin doğruluğunu her zaman iki kez kontrol edin.
- Taşıma aracını Bazel 7 ile kullanın (Bazel 8 ile desteklenmez).
Taşıma aracını kullanma
Başlamadan önce:
- Hem WORKSPACE hem de Bzlmod için güçlü destek sağlayan en son Bazel 7 sürümüne yükseltin.
Aşağıdaki komutun projenizin ana derleme hedefleri için başarıyla çalıştığını doğrulayın:
bazel build --nobuild --enable_workspace --noenable_bzlmod <targets>
Komut dosyasını çalıştırma komutu
Ön koşullar karşılandıktan sonra taşıma aracını kullanmak için aşağıdaki komutları çalıştırın:
# Clone the Bazel Central Registry repository git clone https://github.com/bazelbuild/bazel-central-registry.git cd bazel-central-registry # Build the migration tool bazel build //tools:migrate_to_bzlmod # Create a convenient alias for the tool alias migrate2bzlmod=$(realpath ./bazel-bin/tools/migrate_to_bzlmod) # Navigate to your project's root directory and run the tool cdmigrate2bzlmod -t
Bu komut dosyası tarafından oluşturulan dosyalar
MODULE.bazel
- Bzlmod'un merkezi manifest dosyası. Projenin meta verilerini ve diğer Bazel modüllerine olan doğrudan bağımlılıklarını bildirir.migration_info.md
- Gerekirse taşıma işleminin manuel olarak tamamlanmasına yardımcı olmak için tasarlanmış, taşıma aracının nasıl yürütüldüğüne dair adım adım talimatlar içeren bir dosya.resolved_deps.py
- Geçiş sırasında referans olarak kullanılan, projeninWORKSPACE
dosyası analiz edilerek oluşturulan, projenin harici bağımlılıklarının kapsamlı bir listesini içerir.query_direct_deps
- ProjeninWORKSPACE
dosyasında Bazel,--output=build
ile çağrılarak elde edilen, kullanılan hedeflerle ilgili taşıma işlemine uygun bilgileri içerir. Bu dosya öncelikli olarak taşıma komut dosyası tarafından kullanılır.extension_for_XXX
: Modül uzantısı tanımı içeren bir dosya. Taşıma aracı, standart Bazel modülleri olmayan ancak Bzlmod'un modül uzantıları kullanılarak yönetilebilen bağımlılıklar için bu dosyaları oluşturur.
Bayraklar
Bu taşıma komut dosyalarında kullanılabilen işaretler şunlardır:
--t
/--target
: Taşınacak hedefler. Bu işaret tekrarlanabilir ve hedefler biriktirilir.--i
/--initial
:MODULE.bazel
,resolved_deps.py
,migration_info.md
dosyalarını siler ve sıfırdan başlar. Doğrudan bağımlılıkları algılayın, bunları MODULE.bazel'e ekleyin ve çözümlenmiş bağımlılıkların oluşturulmasını yeniden çalıştırın.
Taşıma sonrası temizlik
migration_info.md
,resolved_deps.py
vequery_direct_deps
öğelerini silin.- Taşıma için kullanılan
MODULE.bazel
dosyasındaki yorumları (ör.# -- bazel_dep definitions -- #
) temizleyin.
Taşıma Örneği
Taşıma komut dosyasının nasıl çalıştığını görmek için Python, Maven ve Go bağımlılıklarının WORKSPACE
dosyasında tanımlandığı aşağıdaki senaryoyu inceleyin.
WORKSPACE
dosyasını görmek için burayı tıklayın
workspace(name="example")
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
load(":my_custom_macro.bzl", "my_custom_macro")
http_archive(
name = "rules_cc",
sha256 = "b8b918a85f9144c01f6cfe0f45e4f2838c7413961a8ff23bc0c6cdf8bb07a3b6",
strip_prefix = "rules_cc-0.1.5",
urls = ["https://github.com/bazelbuild/rules_cc/releases/download/0.1.5/rules_cc-0.1.5.tar.gz"],
)
# Module dependency
# -------------------
http_archive(
name = "rules_shell",
sha256 = "3e114424a5c7e4fd43e0133cc6ecdfe54e45ae8affa14fadd839f29901424043",
strip_prefix = "rules_shell-0.4.0",
url = "https://github.com/bazelbuild/rules_shell/releases/download/v0.4.0/rules_shell-v0.4.0.tar.gz",
)
# Repo rule
# -------------------
http_archive(
name = "com_github_cockroachdb_cockroach",
sha256 = "6c3568ef244ce6b874694eeeecb83ed4f5d5dff6cf037c952ecde76828a6c502",
strip_prefix = "cockroach-22.1.6",
url = "https://github.com/cockroachdb/cockroach/archive/v22.1.6.tar.gz",
)
# Module extension
# -------------------
# Macro which invokes repository_rule
my_custom_macro(
name = "my_custom_repo",
)
# Go dependencies
# -------------------
http_archive(
name = "io_bazel_rules_go",
integrity = "sha256-M6zErg9wUC20uJPJ/B3Xqb+ZjCPn/yxFF3QdQEmpdvg=",
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.48.0/rules_go-v0.48.0.zip",
"https://github.com/bazelbuild/rules_go/releases/download/v0.48.0/rules_go-v0.48.0.zip",
],
)
http_archive(
name = "bazel_gazelle",
integrity = "sha256-12v3pg/YsFBEQJDfooN6Tq+YKeEWVhjuNdzspcvfWNU=",
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.37.0/bazel-gazelle-v0.37.0.tar.gz",
"https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.37.0/bazel-gazelle-v0.37.0.tar.gz",
],
)
load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies")
load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies", "go_repository")
go_rules_dependencies()
go_register_toolchains(version = "1.23.1")
gazelle_dependencies()
go_repository(
name = "org_golang_x_net",
importpath = "golang.org/x/net",
sum = "h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=",
version = "v0.0.0-20190311183353-d8887717615a",
build_file_proto_mode = "disable",
build_naming_convention = "import",
)
# Python dependencies
# -------------------
http_archive(
name = "rules_python",
integrity = "sha256-qDdnnxOC8mlowe5vg5x9r5B5qlMSgGmh8oFd7KpjcwQ=",
strip_prefix = "rules_python-1.4.0",
url = "https://github.com/bazelbuild/rules_python/releases/download/1.4.0/rules_python-1.4.0.tar.gz",
)
load("@rules_python//python:repositories.bzl", "py_repositories")
py_repositories()
load("@rules_python//python:pip.bzl", "pip_parse")
pip_parse(
name = "my_python_deps",
requirements_lock = "@example//:requirements_lock.txt",
)
load("@my_python_deps//:requirements.bzl", "install_deps")
install_deps()
load("@rules_python//python:repositories.bzl", "python_register_toolchains")
python_register_toolchains(
name = "python_3_11",
python_version = "3.11",
)
# Maven dependencies
# __________________
RULES_JVM_EXTERNAL_TAG = "4.5"
RULES_JVM_EXTERNAL_SHA = "b17d7388feb9bfa7f2fa09031b32707df529f26c91ab9e5d909eb1676badd9a6"
http_archive(
name = "rules_jvm_external",
strip_prefix = "rules_jvm_external-%s" % RULES_JVM_EXTERNAL_TAG,
sha256 = RULES_JVM_EXTERNAL_SHA,
url = "https://github.com/bazelbuild/rules_jvm_external/archive/%s.zip" % RULES_JVM_EXTERNAL_TAG,
)
load("@rules_jvm_external//:repositories.bzl", "rules_jvm_external_deps")
rules_jvm_external_deps()
load("@rules_jvm_external//:setup.bzl", "rules_jvm_external_setup")
rules_jvm_external_setup()
load("@rules_jvm_external//:defs.bzl", "maven_install")
maven_install(
name = "px_deps",
artifacts = [
"org.antlr:antlr4:4.11.1",
],
repositories = [
"https://repo1.maven.org/maven2",
],
)
Ayrıca, modül uzantısının kullanımını göstermek için WORKSPACE
konumundan özel makro çağrılır ve my_custom_macro.bzl
konumunda tanımlanır.
my_custom_macro.bzl
dosyasını görmek için burayı tıklayın
"""Repo rule and macro used for testing"""
def _test_repo_rule_impl(repository_ctx):
repository_ctx.file(
"BUILD",
content = """
genrule(
name = "foo",
outs = ["rule_name.out"],
cmd = "touch $@",
visibility = ["//visibility:public"],
)
"""
)
_test_repo_rule = repository_rule(
implementation = _test_repo_rule_impl,
)
def my_custom_macro(name):
_test_repo_rule(name = name)
Nihai hedef, kullanıcı deneyimini etkilemeden MODULE.bazel
dosyasını oluşturmak ve WORKSPACE
dosyasını silmektir.
İlk adım, Taşıma Aracı Nasıl Kullanılır? başlıklı makaledeki talimatları uygulamaktır. Bu adımda çoğunlukla Bazel sürümünün kontrol edilmesi (Bazel 7 olmalıdır) ve taşıma komut dosyasına bir takma ad eklenmesi gerekir.
Ardından, migrate2bzlmod -t=//...
çıktısı çalıştırılır:
bazel 7.6.1 Generating ./resolved_deps.py file - It might take a while... RESOLVED:rules_java
has been introduced as a Bazel module. RESOLVED:bazel_gazelle
has been introduced as a Bazel module. RESOLVED:io_bazel_rules_go
has been introduced as a Bazel module. RESOLVED:rules_python
has been introduced as a Bazel module. IMPORTANT: 3.11 is used as a default python version. If you need a different version, please change it manually and then rerun the migration tool. RESOLVED:my_python_deps
has been introduced as python extension. RESOLVED:org_golang_x_net
has been introduced as go extension. RESOLVED:rules_jvm_external
has been introduced as a Bazel module. RESOLVED:org.antlr
has been introduced as maven extension. RESOLVED:rules_shell
has been introduced as a Bazel module. Congratulations! All external repositories needed for building //... are available with Bzlmod! IMPORTANT: Fix potential build time issues by running the following command: bazel build --enable_bzlmod --noenable_workspace //... IMPORTANT:For details about the migration process, check `migration_info.md` file.
Bu rapor aşağıdaki önemli bilgileri sağlar:
./resolved_deps.py
dosyanızı kullanarak bildirilen ve yüklenen tüm harici depolarla ilgili bilgileri içeren./resolved_deps.py
dosyası oluşturur.WORKSPACE
RESOLVED
anahtar kelimesi, araç tarafından çözülen veMODULE.bazel
dosyasına eklenen tüm bağımlılıkları açıklar.IMPORTANT
anahtar kelimesi, zaman ayırmaya değer önemli bilgileri tanımlar.- Bu örnekte tüm bağımlılıklar en az
--nobuild
işaretiyle çözülmüştür. - Tam derlemeyi (belirtilen komut) çalıştırmak ve olası hataları (ör. araç zinciri doğru şekilde kaydedilmemiş) manuel olarak düzeltmek önemlidir.
migration_info.md
dosyası, taşıma işlemiyle ilgili ayrıntıları içerir. Ayrıntıları bu bölümde bulabilirsiniz.
Dönüşümler
Bu bölümde, kodun WORKSPACE
dosyasından MODULE.bazel
dosyasına taşınması gösterilmektedir.
WORKSPACE - Bazel Module
http_archive( name = "rules_shell", sha256 = "3e114424a5c7e4fd43e0133cc6ecdfe54e45ae8affa14fadd839f29901424043", strip_prefix = "rules_shell-0.4.0", url = "https://github.com/bazelbuild/rules_shell/releases/download/v0.4.0/rules_shell-v0.4.0.tar.gz", )
MODULE.bazel - Bazel Modülü
bazel_dep(name = "rules_shell", version = "0.6.1")
WORKSPACE - Go Extension
http_archive( name = "io_bazel_rules_go", integrity = "sha256-M6zErg9wUC20uJPJ/B3Xqb+ZjCPn/yxFF3QdQEmpdvg=", urls = [ "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.48.0/rules_go-v0.48.0.zip", "https://github.com/bazelbuild/rules_go/releases/download/v0.48.0/rules_go-v0.48.0.zip", ], ) http_archive( name = "bazel_gazelle", integrity = "sha256-12v3pg/YsFBEQJDfooN6Tq+YKeEWVhjuNdzspcvfWNU=", urls = [ "https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.37.0/bazel-gazelle-v0.37.0.tar.gz", "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.37.0/bazel-gazelle-v0.37.0.tar.gz", ], ) load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies") load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies", "go_repository") go_rules_dependencies() go_register_toolchains(version = "1.23.1") gazelle_dependencies() go_repository( name = "org_golang_x_net", importpath = "golang.org/x/net", sum = "h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=", version = "v0.0.0-20190311183353-d8887717615a", build_file_proto_mode = "disable", build_naming_convention = "import", )
MODULE.bazel - Go Extension
go_deps = use_extension("@bazel_gazelle//:extensions.bzl", "go_deps") go_sdk = use_extension("@io_bazel_rules_go//go:extensions.bzl", "go_sdk") go_deps.from_file(go_mod = "//:go.mod") use_repo(go_deps, "org_golang_x_net") go_sdk.from_file(go_mod = "//:go.mod") go_deps.gazelle_override( path = "golang.org/x/net", directives = [ "gazelle:proto disable", "gazelle:go_naming_convention import", ], )
WORKSPACE - Python Extension
http_archive( name = "rules_python", integrity = "sha256-qDdnnxOC8mlowe5vg5x9r5B5qlMSgGmh8oFd7KpjcwQ=", strip_prefix = "rules_python-1.4.0", url = "https://github.com/bazelbuild/rules_python/releases/download/1.4.0/rules_python-1.4.0.tar.gz", ) load("@rules_python//python:repositories.bzl", "py_repositories") py_repositories() load("@rules_python//python:pip.bzl", "pip_parse") pip_parse( name = "my_python_deps", requirements_lock = "@example//:requirements_lock.txt", ) load("@my_python_deps//:requirements.bzl", "install_deps") install_deps() load("@rules_python//python:repositories.bzl", "python_register_toolchains") python_register_toolchains( name = "python_3_11", python_version = "3.11", )
MODULE.bazel - Python Uzantısı
pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip") pip.parse( hub_name = "my_python_deps", python_version = "3.11", requirements_lock = "//:requirements_lock.txt", ) use_repo(pip, "my_python_deps") python = use_extension("@rules_python//python/extensions:python.bzl", "python") python.defaults(python_version = "3.11") python.toolchain(python_version = "3.11")
WORKSPACE - Maven Extension
RULES_JVM_EXTERNAL_TAG = "4.5" RULES_JVM_EXTERNAL_SHA = "b17d7388feb9bfa7f2fa09031b32707df529f26c91ab9e5d909eb1676badd9a6" http_archive( name = "rules_jvm_external", strip_prefix = "rules_jvm_external-%s" % RULES_JVM_EXTERNAL_TAG, sha256 = RULES_JVM_EXTERNAL_SHA, url = "https://github.com/bazelbuild/rules_jvm_external/archive/%s.zip" % RULES_JVM_EXTERNAL_TAG, ) load("@rules_jvm_external//:repositories.bzl", "rules_jvm_external_deps") rules_jvm_external_deps() load("@rules_jvm_external//:setup.bzl", "rules_jvm_external_setup") rules_jvm_external_setup() load("@rules_jvm_external//:defs.bzl", "maven_install") maven_install( name = "px_deps", artifacts = [ "org.antlr:antlr4:4.11.1", ], repositories = [ "https://repo1.maven.org/maven2", ], )
MODULE.bazel - Maven Uzantısı
bazel_dep(name = "rules_jvm_external", version = "6.8") maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven") use_repo(maven, "px_deps") maven.artifact( name = "px_deps", group = "org.antlr", artifact = "antlr4", version = "4.11.1" )
WORKSPACE - Repo rule
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( name = "com_github_cockroachdb_cockroach", sha256 = "6c3568ef244ce6b874694eeeecb83ed4f5d5dff6cf037c952ecde76828a6c502", strip_prefix = "cockroach-22.1.6", url = "https://github.com/cockroachdb/cockroach/archive/v22.1.6.tar.gz", )
MODULE.bazel - Repo rule
http_archive = use_repo_rule("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( name = "com_github_cockroachdb_cockroach", url = "https://github.com/cockroachdb/cockroach/archive/v22.1.6.tar.gz", sha256 = "6c3568ef244ce6b874694eeeecb83ed4f5d5dff6cf037c952ecde76828a6c502", strip_prefix = "cockroach-22.1.6", )
WORKSPACE - Module extension
load(":my_custom_macro.bzl", "my_custom_macro") my_custom_macro( name = "my_custom_repo", )
MODULE.bazel - Module extension
extension_for_my_custom_macro = use_extension("//:extension_for_my_custom_macro.bzl", "extension_for_my_custom_macro") use_repo(extension_for_my_custom_macro, "my_custom_repo")
extension_for_my_custom_macro.bzl
load("//:my_custom_macro.bzl", "my_custom_macro") def _extension_for_my_custom_macro_impl(ctx): my_custom_macro( name = "my_custom_repo", ) extension_for_my_custom_macro = module_extension(implementation = _extension_for_my_custom_macro_impl)
Hata ayıklamayla ilgili ipuçları
Bu bölümde, Bzlmod taşıma işlemi sırasında ortaya çıkabilecek sorunların hata ayıklamasına yardımcı olacak faydalı komutlar ve bilgiler yer alır.
Faydalı ipuçları
Sürümü geçersiz kılma: Bir bağımlılığın sürümünü yükseltmek nadir de olsa sorunlara neden olabilir. Bzlmod, MVS algoritması nedeniyle bağımlılığın sürümünü değiştirebilir. WORKSPACE'tekiyle aynı veya benzer bir sürümü kullanmak için single_version_override ile geçersiz kılın. Bu özelliğin, WORKSPACE ile Bzlmod arasındaki farklılıkları ayıklamak için yararlı olduğunu ancak uzun vadede bu özelliğe güvenmemeniz gerektiğini unutmayın.
single_version_override(module_name = "{dep_name}", version = "{version}")
bazel mod komutunu kullanın.
Belirtilen bir deponun sürümünü
show_repo
komutuyla kontrol edin. Örneğin:bazel mod show_repo @rules_python
show_extension
komutuyla bir modül uzantısı hakkındaki bilgileri kontrol edin. Örneğin:bazel mod show_extension @rules_python//python/extensions:pip.bzl%pip
Deponun kaynağını izlemek veya kontrol etmek istediğinizde deponun yerel bir kopyasını oluşturmak için sağlayıcı modunu kullanın. Örneğin:
bazel vendor --enable_bzlmod --vendor_dir=vendor_src --repo=@protobuf
Taşıma raporu oluşturma
Bu dosya, taşıma komut dosyası her çalıştırıldığında güncellenir. İlk çalıştırma işleminde veya --i
işareti kullanıldığında ise sıfırdan oluşturulur. Rapor şunları içerir:
- Yerel test için komut.
- Doğrudan bağımlılıkların listesi (en azından projede doğrudan kullanılanlar).
Her bağımlılık için,
WORKSPACE
dosyasında deponun nerede tanımlandığını kontrol etmeye yönelik bir açılır menü. Bu menü özellikle hata ayıklama için kullanışlıdır. Şu şekilde görebilirsiniz:> Click here to see where and how the repo was declared in the WORKSPACE file
Her bağımlılık için
MODULE.bazel
dosyasında nasıl uygulandığı. Önceki Taşıma Örneği'ne göre bu şöyle görünür:Bazel modülü bağımlılığı -
Migration of rules_python
Found perfect name match in BCR: rules_python Found partially name matches in BCR: rules_python_gazelle_plugin It has been introduced as a Bazel module: `bazel_dep(name = "rules_python", version = "1.6.1")`
- Komut dosyası, bulursa otomatik olarak
perfect name match
öğesini kullanır. Hata durumunda, adın doğru şekilde eklenip eklenmediğini tekrar kontrol edebilirsiniz.
- Komut dosyası, bulursa otomatik olarak
Python uzantısı -
Migration of my_python_deps
pip.parse( hub_name = "my_python_deps", requirements_lock = "//:requirements_lock.txt", python_version = "3.11", ) use_repo(pip, "my_python_deps")
Maven uzantısı -
Migration of org.antlr (px_deps):
maven.artifact( name = "px_deps", group = "org.antlr", artifact = "antlr4", version = "4.11.1" )
Go uzantısı -
Migration of org_golang_x_net
go_deps.from_file(go_mod = "//:go.mod") go_sdk.from_file(go_mod = "//:go.mod") go_deps.gazelle_override( path = "golang.org/x/net", directives = [ "gazelle:proto disable", "gazelle:go_naming_convention import", ], )
go.mod
'nın yardımıyla Go modülü olarak kullanıma sunulmuştur.go.mod
vego.sum
kullanılamıyorsa go modülü doğrudanMODULE.bazel
dosyasına eklenir.gazelle_override
, belirli yönergeleri eklemek için kullanılır.
Faydalı bağlantı
- Harici uzantıların resmi sayfaları
- Topluluk gönderileri ve videoları
Geri bildirim
Katkıda bulunmak isterseniz bazel-central-registry adresinde bir sorun veya PR oluşturarak bunu yapabilirsiniz.