Trình soạn thảo dựa trên CDT, Phần 1 : Mô hình công cụ phát triển C/C++

Khám phá các lớp có chứa thông tin của CDT

Dự án “Công cụ phát triển Eclipse C/C++ (CDT)” vẫn là một trong những phần tải sẵn có phổ biến nhất của Eclipse. Tuy nhiên, sự phong phú của môi trường phát triển được tích hợp (IDE’s) khiến mã nguồn trở nên khó hiểu và khó tuỳ chỉnh, đây là mối quan tâm quan trọng cho các tổ chức đang cố gắng để tích hợp các CDT vào các ứng dụng của họ. Loạt bài viết gồm năm phần "Trình soạn thảo dựa trên CDT" sẽ giải thích cách trình soạn thảo CDT làm việc và Phần 1 giới thiệu các cấu trúc dữ liệu mà trên đó CDT hoạt động.

Matthew Scarpino, Phát triển Java, Eclipse Engineering, LLC

Matthew Scarpino là nhà quản lý dự án và nhà phát triển Java tại Eclipse Engineering LLC. Ông là tác giả hàng đầu của SWT/JFace in Action và có đóng góp nhỏ nhưng quan trọng vào Standard Widget Toolkit (SWT). Ông thích nhạc dân gian Ailen, chạy maratông, thơ của William Blake, và Graphical Editing Framework (GEF).



09 09 2010

Tôi đã nghĩ rằng đã thuyết phục được ông chủ của mình về CDT, nhưng ông ta nói có quá nhiều tính năng. Hoá ra là ông chỉ quan tâm đến trình soạn thảo mã nguồn – tô màu cú pháp, phân tích cú pháp tự động và đặc biệt là hoàn thành mã. Ông hỏi tôi có thể tuỳ chỉnh các trình soạn thảo và thêm nó vào ứng dụng Rich Client Platform (RCP) của chúng không. Tôi trả lời: "Không thành vấn đề. Đó là Eclipse! Sẽ khó đến mức nào đây ?"

Quả thực là rất khó. Hiện tại công cụ CDT phiên bản 3.1 bao gồm 20 trình cắm thêm, chứa hơn 100 gói và hàng ngàn giao diện và lớp. Tìm hiểu được cỗ máy là một nỗ lực lâu dài. Nhưng cuối cùng tôi đã làm hài lòng ông chủ của mình bằng một trình soạn thảo đang hoạt động và tôi rất hạnh phúc khi chia sẻ những gì tôi đã học được.

Ta có thể nói rằng CDT là mã nguồn mở C/C++ IDE sẵn có tốt nhất. Ngoài việc soạn thảo đầy đủ các đặc trưng, gỡ lỗi và lập chỉ mục, nó cung cấp sự linh hoạt tuyệt vời trong việc kiểm soát quá trình xây dựng. Nếu bạn không muốn viết tệp Makefile riêng, nó tạo ra cho bạn tệp và cập nhật tệp đó trong suốt dự án của bạn. Bạn có thể truy cập vào bộ sưu tập trình biên dịch của GNU (GNU Compiler Collection (GCC)) và các ứng dụng C/C++ của GNU khác trong CDT, mà bạn cũng có thể tích hợp mọi nguồn mở khác hoặc mọi dãy công cụ thương mại.

Hãng QNX Inc. đề xuất CDT vào năm 2002 và đã thực hiện vai trò của nhà phát triển và nhà bảo trì chính. Phần lớn các mã được dựa trên các công cụ phát triển Java (Java Development Tools (JDT)) của Eclipse, nhưng hãng QNX (cụ thể là Doug Schaefer) đã bổ sung nhiều khả năng, bao gồm các phân tích cú pháp cho C/C++ nâng cao, các dự án dựng phần mềm được quản lí/ theo chuẩn và các quá trình dựng phần mềm theo cấu hình. Nếu muốn biết thêm thông tin, bạn chỉ cần xem trang Eclipse CDT hoặc blog được viết rất tốt của Doug Schaefer (xem phần Tài nguyên).

CDT lược giản

Mục đích của loạt bài này là cung cấp cho bạn hiểu biết về soạn thảo CDT để bạn có thể xây dựng công cụ C/C++ tuỳ chỉnh. Để làm cho quá trình này trở nên dễ dàng hơn, tôi đã tạo ra một phiên bản lược giản của phiên bản CDT đầy đủ mà tôi gọi là CDT lược giản Bare Bones CDT (BBCDT) (xem phầnTải về mã này). Tôi đã gỡ bỏ phần lớn các lớp của CDT, nhưng vẫn giữ nguyên các quy ước về tên gọi - một phần để đơn giản hóa quá trình thêm mã CDT vào BBCDT, và một phần do tôi lười.

BBCDT chỉ chứa hai trình cắm thêm: org.dworks.bbcdt.core (trình cắm thêm lõi) và org.dworks.bbcdt.ui (trình cắm thêm giao diện người dùng (UI)). Trình cắm thêm đầu tiên cung cấp các lớp và các giao diện tạo nên mô hình CDT. Trình cắm thêm thứ hai tạo ra các UI, bao gồm giao diện CEditor, các lớp liên quan của nó, và các hướng dẫn từng bước (wizard) và các trang cần thiết để tạo các tệp nguồn và các dự án mới.

Đối với bài viết đầu tiên này, BBCDT không làm được điều thú vị nào ngoại trừ việc cho biết cách các lớp CDT căn bản tương tác với nhau. Các bài tiếp theo giải thích cách CDT thực hiện việc phân vùng, tô màu cú pháp, phân tích cú pháp và hoàn thành mã. Các bài viết này cũng sẽ bàn rộng về BBCDT và đảm bảo rằng các đặc tính này được bổ sung vào mã.


Các phần tử của mô hình CDT

Mã nguồn Java™ thông thường truy cập các tệp và các thư mục thông qua các đối tượng File. Tuy nhiên, để thực hiện các hoạt động cụ thể của Eclipse tại các tệp trong không gian làm việc, thì bạn cần phải có các bộ thích nghi (adapter) tại giao diện chương trình ứng dụng tài nguyên (API):

  • IFile
  • IProject
  • IFolder
  • IWorkspaceRoot

Ngoài việc cung cấp việc truy cập tệp, các bộ thích nghi IResource này cung cấp cấu trúc không gian làm việc. Nguồn tài nguyên mức trên là IWorkspaceRoot, và nguồn tài nguyên con của nó là IProject. Mỗi IProject lại chứa IFolderIFile. Cho đến nay, mọi việc vẫn diễn ra tốt đẹp.

Mô hình CDT trình bày một bộ khác nhưng tương tự với bộ thích nghi đối với các nguồn tài nguyên không gian làm việc. Hình 1 mô tả hệ thống phân cấp thừa kế của chúng.

Hình 1. Hệ thống phân cấp các phần tử của mô hình CDT
Hệ thống phân cấp các phần tử của mô hình CDT

Hình 2 cho thấy cách CDT sử dụng các phần tử để cấu trúc không gian làm việc của nó. Ở phía trên, ICModel chứa các lớp ICContainerICProject. ICProject chứa các ISourceRoot hoạt động giống như các gói JDT, nhưng có thể chứa các mã tại các vị trí khác nhau trên hệ thống tệp. Để quản lý các địa điểm này, ISourceRoot chứa các cá thể ISourceEntry từng cá thể giữ một đường dẫn IPath tới nguồn khác nhau. Mỗi ICElement lại có một tên và phương thức cụ thể để truy cập vào IResource nằm dưới nó.

Hình 2. Cấu trúc không gian làm việc của CDT
Cấu trúc không gian làm việc của CDT

Bộ biên dịch ITranslationUnit

Bộ biên dịch ITranslationUnit dưới dạng tệp đơn mã C/C++ và là phần tử quan trọng nhất trong mô hình CDT. Mỗi một đơn vị đều có các đơn vị con biểu diễn các khía cạnh khác nhau của tệp mã nguồn, chẳng hạn như IInclude, IUsingINamespace. (Tôi sẽ thảo luận về cơ cấu ITranslationUnit cụ thể hơn nhiều trong các trao đổi về phân tích cú pháp của CDT.)

Ngoài ra, mỗi ITranslationUnit lại giữ một IWorkingCopy đơn để quản lý các thay đổi không được ghi lưu vào mã. Cả ITranslationUnitIWorkingCopy lưu giữ nội dung của chúng trong các cá thể IBufferCache riêng rẽ mà được phân bố vị trí bởi một BufferManager và hoạt động giống như bộ nhứ truy cập nhanh LRU (Least Recently Used). Đây là chủ đề liên quan, nhưng nếu bạn quan tâm thì hãy nghiên cứu gói org.dworks.bbcdt.internal.core.util.

Các đối tượng Info (Thông tin)

Mỗi đối tượng ICModel, ICContainer, ICProjectITranslationUnit đều có một đối tượng thông tin tương ứng (CModelInfo, CContainerInfo, v.v.) Những đối tượng thông tin này có chứa các tham chiếu đến các con của phần tử và cung cấp các truy cập đến chúng. Nếu bạn muốn có danh sách các ICProject trong CModel, hãy gọi phương thức CModel.getCProjects(), cho phép gọi phương thức CModelInfo.getChildren(). CDT tạo ra một đối tượng thông tin khi phần tử này được mở lần đầu và loại bỏ nó khi phần tử này được đóng lại.


Ba giai đoạn của mô hình CDT

Bây giờ bạn biết các thành phần cơ bản của mô hình, bạn cần phải biết cách chúng tương tác với nhau như thế nào trong hoạt động CDT. Vòng đời của một mô hình CDT bao gồm ba bước quan trọng: Khởi tạo mô hình ban đầu, tạo ra đối tượng CProject và tạo ra bộ TranslationUnit trong trình soạn thảo của CDT.

Các thành phần của mô hình CDT và IAdapters

Giống như các tài nguyên hình thành nên bàn làm việc Eclipse, các thành phần của mô hình CDT (ICModel, ICProject, ITranslationUnit, vv.) đều là sau giao diện IAdaptable. Giao diện này cho phép CDT bổ sung các chức năng cụ thể của nó cho các lớp đã có mà không cần phải phân lớp chúng. Với quan điểm mã hóa thì một IAdaptable có thể gắn kết đến một lớp khác bằng cách sử dụng phương thức getAdapter (Class adapter) (Bộ thích nghi lớp) của nó.

Đối với mỗi phần tử, CDT cung cấp một lớp thực hiện (CModel, CProject, TranslationUnit, v.v.) với các phương thức được định nghĩa đầy đủ. Tuy nhiên, bằng cách sử dụng giao diện IAdaptable, bạn có thể tạo các phần tử C/C++ riêng mà không làm mất các khả năng hiện có của các ICElement. Điều đó có nghĩa là các phần tử mới của bạn có thể thích ứng với các phần tử CDT theo cùng cách mà các phần tử CDT thích ứng với các tài nguyên trong không gian làm việc của Eclipse.

Bước 1: Tạo mô hình CDT

Khi bàn làm việc khởi tạo các trình cắm thêm của CDT, thì trình cắm thêm lõi tạo ra lớp CoreModel đơn (không phải là CModel). Quá trình này lần lượt tạo ra các cá thể của hai lớp quan trọng là các lớp PathEntryManagerCModelManager. Lớp PathEntryManager theo dõi những thư mục cần thiết cho quy trình dựng phần mềm, chẳng hạn gồm các thư mục và các thư viện hàm macro. Trong mô hình CDT, một đường dẫn cho mỗi thư mục nằm trong đối tượng SourceEntry .

Nhưng lớp CModelManager là trung tâm của bài thảo luận này. Nó giữ nhiều vai trò quan trọng trong CDT: :

  • Tạo ra CModel để dùng như phần tử mức cao trong hệ thống phân cấp các phần tử
  • Thêm và loại bỏ các phần tử mô hình mới khi các tài nguyên của chúng được tạo ra hoặc bị xóa bỏ
  • Theo dõi các phần tử mô hình và các đối tượng thông tin của chúng
  • Giữ ánh xạ của TranslationUnit và các con WorkingCopy của chúng
  • Lưu giữ bộ nhớ truy cập nhanh của các phần tử hiện đang mở
  • Đáp ứng các thay đổi trong các kiểu nội dung của tài nguyên
  • Đáp ứng các những thay đổi trong bộ miêu tả tài nguyên

Các chức năng quan trọng nhất là hai chức năng đầu tiên. CModelManager dùng như một nhà máy sản xuất mô hình của CDT và bắt đầu hoạt động bằng cách tạo các đối tượng CModel. Sau đó nó lắng nghe các thay đổi của tài nguyên trong không gian làm việc và cập nhật mô hình mỗi khi một phần tử CDT bị tác động.

Khi bất cứ nguồn tài nguyên nào được tạo, bị xóa, hoặc bị sửa, thì không gian làm việc của Eclipse tạo IResourceDelta cho phép lưu giữ cấu trúc phân cấp cũ và mới. Trình quản lý phân tích lớp này bằng trình xử lý DeltaProcessor, quyết định liệu nguồn tài nguyên bị ảnh hưởng có là CElement hay không. Nếu đúng, nó tạo ra một phần tử mới tương ứng với tài nguyên và thêm nó vào danh sách các con của các phần tử cha.

Chức năng của CModelManager trong BBCDT thực hiện tất cả các chức năng trên, ngoại trừ hai chức năng cuối. Kiểu nội dung của tài nguyên được thiết lập bởi <content-type> nêu trong tệp plugin.xml, và một tệp mô tả được tạo ra để mô tả dự án mới.

Bước 2: Tạo một dự án CProject mới

CDT cung cấp một cấu trúc hướng dẫn từng bước mở rộng được để tạo tài nguyên của CDT. Hướng dẫn từng bước cho Dự án mới là đặc biệt mạnh, cho phép bạn định cấu hình mọi khía cạnh của quá trình dựng phần mềm của dự án, từ các biến môi trường đến lập chỉ mục nguồn. Khi bạn hoàn thành hướng dẫn từng bước, nó và trình cắm thêm lõi sẽ thực hiện bốn nhiệm vụ chính:

  1. Tạo và mở một IProject tại đường dẫn đã cho
  2. Xây dựng một IProjectDescription để giữ thông tin chung của IProject
  3. Kiến thiết CDescriptor để giữ các thông tin cụ thể CDT
  4. Tạo cho IProject một CNature hoặc CCNature, tùy theo kiểu nội dung

Bước đầu và thứ hai là phổ biến để tạo bất kỳ IProject nào. Trong nhiệm vụ thứ hai, IProjectDescription lưu giữ các thông tin mà bàn làm việc sử dụng để xác định dự án. Dữ liệu này được giữ lại ở dạng XML trong tệp của dự án tại thư mục mức cao của dự án. Hai phần tử quan trọng là <buildSpec></buildSpec>, liệt kê các câu lệnh dựng phần mềm cho dự án và <natures></natures>, cho phép đánh dấu dự án này có các đặc điểm ngoài các đặc điểm của IProject thông thường.

CDescriptor trong bước thứ ba tương tự như IProjectDescription. Sự khác biệt chính là nó chứa các dữ liệu đặc biệt cho CDT và chèn các thông tin này trong tệp Cdtproject tách biệt, chứa mô tả về các công cụ khác nhau sử dụng trong quá trình dựng phần mềm và xác định các tham số cấu hình cho từng công cụ. Tệp này sử dụng định dạng XML tương tự với IProjectDescription. Liệt kê 1 là một ví dụ về khai báo mô tả tệp .cdtproject.

Liệt kê 1. Các thông tin của lược khai trong tệp .cdtproject.
<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
  <buildOutputProvider> 
    <openAction enabled="false" filePath=""/>
    <parser enabled="true"/> 
  </buildOutputProvider> 
  <scannerInfoProvider id="makefileGenerator"> 
    <runAction arguments="-f ${project_name}_scd.mk" command="make" 
          useDefault="true"/> 
    <parser enabled="false"/>
  </scannerInfoProvider> 
</profile>

Bước cuối cùng liên quan đến việc gắn thẻ cho dự án này như dự án C hay C++. Trình cắm thêm của phần lõi thực hiện điều này bằng cách thêm hoặc là lớp CNature hoặc CCNature vào lớp IProjectDescription. Các lớp này không tự làm bất cứ điều gì thú vị, nhưng khi lớp DeltaProcessor ghi nhận bản chất của một dự án mới, thì nó lệnh cho lớp CModelManager tạo một lớp CProject tương ứng với tài nguyên của dự án và bổ sung nó vào mô hình phân cấp của CDT.

Bước 3: Tạo lớp TranslationUnit và WorkingCopy mới

Không giống như lớp CProject, lớp TranslationUnit không được kiến thiết lập tức khi lớp IFile bên dưới nó xuất hiện. Thay vào đó, nó được tạo ra sau khi tệp được kích hoạt và trình soạn thảo mở ra. Để giải thích cách làm này, tôi sẽ bắt đầu với lớp trung tâm của quá trình soạn thảo của CDT: lớp CEditor.

Về cơ bản, CEditor là một điều khiển StyledText thích hợp với bàn làm việc và nhận nội dung từ cá thể IEditorInput. Để ăn khớp với kiến trúc Model-View-Controller (MVC: Mô hình-Khung nhìn-Bộ điều khiển), API của trình soạn thảo văn bản của Eclipse (Eclipse Text Editor) chỉ sử dụng điều khiển này để cung cấp khía cạnh View. Thông tin của trình soạn thảo được đóng gói trong một cá thể của lớp IDocument. Đối tượng SourceViewer hoạt động như bộ điều khiển, và đối tượng CSourceViewer quản lý việc truy cập các tài liệu của CDT.

Trong trình cắm thêm lõi, tệp plugin.xml giữ các phần mở rộng của lớp contentType cho các kiểu khác nhau của các tệp C/C++ và liên kết mỗi lớp contentType với hậu tố của tệp. Trong trình cắm thêm UI, tệp plugin.xml liên kết lớp CEditor với các lớp contentType ghi nhận các tệp có các hậu tố .bbc, .bbcpp, .bbh và .bbhpp. Khi bạn tạo hoặc nhấp đúp vào một trong những tệp này, bàn làm việc chuyển đổi IFile thành IEditorInput và sử dụng nó để khởi tạo CEditor.

Khi trình soạn thảo được khởi tạo, lớp CDocumentProvider sẽ thực hiện ba nhiệm vụ quan trọng sau:

  1. Nó sử dụng IFile đầu vào để tạo các đối tượng TranslationUnitTranslationUnitInfo .
  2. Nó tạo ra lớp IDocument cho trình soạn thảo với các thông tin trong lớp IEditorInput.
  3. Nó xây dựng lớp WorkingCopy cho lớp TranslationUnit và bộ nhớ đệm của nó.

Để tạo các phần tử mới của CDT, bộ cung cấp gọi lớp CoreModel, lớp này gọi lớp CModelManager. Các hoạt động của không gian làm việc này, chẳng hạn như CreateWorkingCopyOperationDestroyWorkingCopyOperation, tất cả thực hiện giao diện IWorkspaceRunnable. Chúng chạy không đồng bộ và ra lệnh cho không gian làm việc ngăn chặn các hoạt động khác làm cản trở việc sửa đổi tài nguyên.

Giống như lớp CProject, mỗi lớp TranslationUnit có các thông tin cấu hình riêng, chẳng hạn như các chú giải. Tuy nhiên, bộ cung cấp không tạo ra một lớp CDescriptor tách biệt. Thay vào đó, nó vẫn giữ các dữ liệu bên trong đối tượng FileInfo của lớp IEditorInput. Bằng cách này, khi đầu vào được kích hoạt trong lần tới, bộ cung cấp có thể truy cập vào các thông tin của đơn vị mà không cần bắt đầu từ đầu.


Chạy BBCDT

Tôi đã cung cấp BBCDT như là trình cắm thêm và dự án trình cắm thêm. Vì mục đích chính của công cụ là cung cấp cơ sở cho công việc về sau, nên tôi đề nghị các bạn nhập vào dự án, thay vì bổ sung thêm khả năng của nó vào cài đặt Eclipse của bạn.

Để làm BBCDT đơn giản nhất có thể, tôi để lại lớp PathEntryManager, có nghĩa là công cụ này không sử dụng các đối tượng SourceEntry hoặc thậm chí SourceRoot. Vì vậy, bạn phải bổ sung thêm các tệp nguồn (các tệp .bbc, .bbh, .bbcc và .bbhh) trực tiếp vào dự án. Để tạo tài nguyên của BBCDT, tôi đã tạo ra một tập mới của các lớp hướng dẫn từng bước theo trang trong gói org.dworks.bbcdt.ui.wizards. Để tạo một dự án, bạn nhấn vàoFile > New > Project và chọn hoặc C hoặc C++ Để tạo một tệp, bạn nhấn New > Other và chọn hoặc ChoặcC++. Hình 3 cho thấy các dự án BBCDT và trình soạn thảo.

Hình 3. BBCDT
The BBCDT

Kết luận

Nếu bạn đã truy cập các lớp IFileIProject trong mã Java của mìnhn, các phần tử của mô hình CDT không hiện vấn đề nào. Đối tượng CModel chứa lớp CProject, mà nó chứa CSourceRoot. Mỗi lớpTranslationUnit tương ứng với một tệp nguồn đơn của C/C++, do đó trình soạn thảo tương tác với mô hình CDT bằng cách truy cập và thay đổi các phần tử đó.

Những điều phức tạp lớn đến cùng với sức mạnh to lớn. Các xử lý này có vẻ quá chi tiết, nhưng bạn sẽ thấy nó hữu ích nếu bạn bắt đầu dựng trình soạn thảo C/C++ riêng. Bạn có thể có ý tưởng tốt hơn về cơ chế CDT bằng cách nghiên cứu mã nguồn của BBCDT. Tôi khuyên bạn nên thêm, loại bỏ và thay đổi mã để thử nghiệm các hoạt động của nó.

Mô hình CDT cũng trở nên rõ ràng hơn trong các bài tiếp, khi tôi trao đổi về nhiều cách mà các đối tượng TranslationUnitWorkingCopy tương tác với CEditor và các lớp UI của nó. Phần 2 đi sâu hơn về cách mà lớp Document uản lý các sự kiện, về cách phân vùng và về cách việc phân vùng này đảm bảo cho việc tô màu cú pháp.


Tải về

Mô tảTênKích thước
Part 1 source codeos-ecl-cdt1.zip574KB

Tài nguyên

Học tập

Lấy sản phẩm và công nghệ

Thảo luận

Bình luận

developerWorks: Đăng nhập

Các trường được đánh dấu hoa thị là bắt buộc (*).


Bạn cần một ID của IBM?
Bạn quên định danh?


Bạn quên mật khẩu?
Đổi mật khẩu

Bằng việc nhấn Gửi, bạn đã đồng ý với các điều khoản sử dụng developerWorks Điều khoản sử dụng.

 


Ở lần bạn đăng nhập đầu tiên vào trang developerWorks, một hồ sơ cá nhân của bạn được tạo ra. Thông tin trong bản hồ sơ này (tên bạn, nước/vùng lãnh thổ, và tên cơ quan) sẽ được trưng ra cho mọi người và sẽ đi cùng các nội dung mà bạn đăng, trừ khi bạn chọn việc ẩn tên cơ quan của bạn. Bạn có thể cập nhật tài khoản trên trang IBM bất cứ khi nào.

Thông tin gửi đi được đảm bảo an toàn.

Chọn tên hiển thị của bạn



Lần đầu tiên bạn đăng nhập vào trang developerWorks, một bản trích ngang được tạo ra cho bạn, bạn cần phải chọn một tên để hiển thị. Tên hiển thị của bạn sẽ đi kèm theo các nội dung mà bạn đăng tải trên developerWorks.

Tên hiển thị cần có từ 3 đến 30 ký tự. Tên xuất hiện của bạn phải là duy nhất trên trang Cộng đồng developerWorks và vì lí do an ninh nó không phải là địa chỉ email của bạn.

Các trường được đánh dấu hoa thị là bắt buộc (*).

(Tên hiển thị cần có từ 3 đến 30 ký tự)

Bằng việc nhấn Gửi, bạn đã đồng ý với các điều khoản sử dụng developerWorks Điều khoản sử dụng.

 


Thông tin gửi đi được đảm bảo an toàn.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=70
Zone=Nguồn mở
ArticleID=518115
ArticleTitle=Trình soạn thảo dựa trên CDT, Phần 1 : Mô hình công cụ phát triển C/C++
publish-date=09092010