Câu hỏi chính là: bạn có muốn tệp cấu hình của mình ở một số ngôn ngữ hoàn chỉnh Turing (giống như Python) không? Nếu bạn làm muốn điều đó, bạn cũng có thể xem xét việc nhúng một số khác (Turing hoàn chỉnh) ngôn ngữ kịch bản như Guile hoặc Lua (bởi vì có thể bị coi là "đơn giản" để sử dụng, hoặc nhúng, hơn Python là; đọc chương về Mở rộng & Nhúng Python ). Tôi sẽ không thảo luận thêm (vì các câu trả lời khác của Amon - đã thảo luận sâu hơn) nhưng lưu ý rằng việc nhúng một ngôn ngữ kịch bản trong ứng dụng của bạn là một lựa chọn kiến trúc chính , mà bạn nên xem xét từ rất sớm; Tôi thực sự không khuyên bạn nên đưa ra lựa chọn đó sau!
Một ví dụ nổi tiếng về một "tập lệnh" có thể cấu hình chương trình là trình soạn thảo GNU emacs (hoặc có thể là AutoCAD trong vương quốc độc quyền); vì vậy, hãy lưu ý rằng nếu bạn chấp nhận kịch bản, một số người dùng cuối cùng sẽ sử dụng - và có thể lạm dụng, theo quan điểm của bạn - cơ sở đó rộng rãi và tạo ra một kịch bản nhiều nghìn dòng; do đó việc lựa chọn một ngôn ngữ kịch bản đủ tốt là rất quan trọng.
Tuy nhiên (ít nhất là trên các hệ thống POSIX), bạn có thể xem xét thuận tiện để cho phép "tệp" cấu hình được tính toán động tại thời điểm khởi tạo (tất nhiên, để lại gánh nặng cấu hình lành mạnh cho quản trị viên hoặc người dùng hệ thống của bạn; thực sự đó là cấu hình văn bản xuất phát từ một số tập tin hoặc từ một số lệnh). Vì thế, bạn có thể đơn giản chấp nhận quy ước (và ghi lại nó) rằng một đường dẫn tệp cấu hình bắt đầu bằng ví dụ a !
hoặc a |
thực sự là một lệnh shell mà bạn sẽ đọc như một đường ống dẫn . Điều này khiến người dùng của bạn có quyền lựa chọn sử dụng bất kỳ "tiền xử lý" hoặc "ngôn ngữ kịch bản" nào mà anh ta quen thuộc nhất.
(bạn cần tin tưởng người dùng của mình về các vấn đề bảo mật nếu bạn chấp nhận cấu hình được tính toán động)
Vì vậy, trong mã khởi tạo của bạn, main
ví dụ , bạn sẽ chấp nhận một số --config
đối số confarg
và nhận một số FILE*configf;
từ nó. Nếu đối số đó bắt đầu bằng !
(tức là nếu (confarg[0]=='!')
....), bạn sẽ sử dụng configf = popen(confarg+1, "r");
và đóng đường ống đó với pclose(configf);
. Nếu không, bạn sẽ sử dụng configf=fopen(confarg, "r");
và đóng tệp đó với fclose(configf);
(đừng quên kiểm tra lỗi). Xem ống (7) , popen (3) , fopen (3) . Đối với một ứng dụng được mã hóa bằng Python, hãy đọc về os.popen , v.v ...
(tài liệu cũng dành cho người dùng kỳ lạ muốn vượt qua tệp cấu hình có tên !foo.config
để vượt qua ./!foo.config
để bỏ qua popen
thủ thuật ở trên)
BTW, một mẹo như vậy chỉ là một sự tiện lợi (để tránh yêu cầu người dùng nâng cao, ví dụ mã một số tập lệnh shell để tạo tệp cấu hình ). Nếu người dùng muốn báo cáo bất kỳ lỗi nào, anh ta nên gửi cho bạn tệp cấu hình đã tạo ...
Lưu ý rằng bạn cũng có thể thiết kế ứng dụng của mình với khả năng sử dụng và tải plugin tại thời điểm khởi tạo, ví dụ như với dlopen (3) (và bạn cần tin tưởng người dùng của mình về plugin đó). Một lần nữa, đây là một quyết định kiến trúc rất quan trọng (và bạn cần xác định và cung cấp một số API và quy ước khá ổn định về các plugin này và ứng dụng của bạn).
Đối với một ứng dụng được mã hóa bằng ngôn ngữ script như Python, bạn cũng có thể chấp nhận một số đối số chương trình cho eval hoặc exec hoặc các nguyên hàm tương tự. Một lần nữa, các vấn đề bảo mật sau đó là mối quan tâm của người dùng (nâng cao) .
Về định dạng văn bản cho tệp cấu hình của bạn (có được tạo hay không), tôi tin rằng bạn chủ yếu cần tài liệu tốt (và việc chọn một số định dạng cụ thể không quan trọng; tuy nhiên tôi khuyên bạn nên để người dùng của mình có thể đặt một số ý kiến -kipped- bên trong nó). Bạn có thể sử dụng JSON (tốt nhất là với một số trình phân tích cú pháp JSON chấp nhận và bỏ qua các nhận xét thông thường //
cho đến khi eol hoặc /*
... */
...), hoặc YAML, hoặc XML, hoặc INI hoặc điều của riêng bạn. Phân tích tệp cấu hình khá dễ dàng (và bạn sẽ tìm thấy nhiều thư viện liên quan đến tác vụ đó).