Hỏi cách sử dụng các project opensource trên github

Mình hiện tại đang muốn làm 1 chương trình nhỏ trên C++ sử dụng library curl để tạo request http lấy dữ liệu, mình có tham khảo các nguồn thì thấy họ bảo nên dùng curl tạo request và 1 thư viện xử lý json trả về, mình có tải về lib của curl thì thấy có 1 folder “include/curl” chứa các file header, folder lib chứ file libcurl.a và libcurl.dll.a , folder bin chứa curl.exe và libcurl.dll để chạy exe, mình dùng Code Block để code chương trình, mình copy folder include vào phần include của mingw trong Code block, copy libcurl.a vào phần lib của mingw, sau khi xong thì mình chạy thử 1 đoạn code example thì thấy có lỗi main.c|11|undefined reference to `_imp__curl_easy_init’|, mình ko biết tại sao lại undefied dù mình đã add lib và header.

Còn nữa là các bạn có thể hướng dẫn mình dùng cái code open source ở đây ko https://github.com/whoshuu/cpr ,
theo mình hiểu thì dùng cmake để tạo makefile để build nhưng mình cmake toàn lỗi (mình test thử với source của curl thì ok), mình thấy tác giả cũng ko hướng dẫn cách dùng thế nào, loay hoay mãi từ hôm qua

libcurl.a là thư viện tĩnh
libcurl.dll là thư viện động
libcurl.dll.a là tập tin giúp chương trình kết nối với thư viện động khi link mấy object file lại thành exe file

add lib path và header path là chưa đủ, phải thêm flag -lcurl vô phần linking nữa

nếu muốn link với thư viện tĩnh thay vì thư viện động như trên thì thêm flag -DCURL_STATICLIB vô phần linking, bỏ -lcurl khỏi phần linking đi.


cách dễ nhất là xài Visual Studio Community 2017 hoặc 2019 và vcpkg :V

  • install VS Community 2019
  • git clone https://github.com/Microsoft/vcpkg/
  • bootstrap-vcpkg.bat
  • vcpkg integrate install
  • vcpkg install cpr
  • mở VS lên, tạo empty project và chạy ngon lành :V :V :V

bạn có thể chê VS nặng này nọ nhưng chờ 9 tiếng rồi mà chưa giải quyết được vấn đề link thư viện thì thôi thà bỏ 2-3 tiếng cài VS và 30 phút cài vcpkg và để nó tự build thư viện curl, cpr, v.v… gì nữa thì có phải lẹ hơn ko :V

4 Likes

May quá có bác trả lời phần này, em cảm ơn bác trước, nếu em biết thằng Visual Studio nó làm đc nhanh vậy thì em đã cài rồi, cứ loay hoay mãi vì ngày xưa em nhớ có đợt làm với mấy cái thư viện của openCV cũng toàn phải add lib bằng tay nên em nghĩ IDE nào nó cũng phải vậy.

Bác cho em hỏi là nếu mình dùng thư viện tĩnh thì mình chỉ cần add file lib.a và nếu dùng thư viện động thì add lib.dll.a à bác, kiểu như mình chỉ chọn dùng 1 trong 2 thằng đúng ko bác, và nếu dùng thư viện động thì mình phải thêm cái file .dll tương ứng vào folder chứa file .exe bác nhỉ, phần lib em hỏi do tò mò cách add thư viện chứ h em qua VS cho nhanh

1 Like

đúng rồi, chọn 1 trong 2 tĩnh hoặc động thôi, mà liên kết động thì khỏi vướng víu mấy cái license LGPL phức tạp :V

khi biên dịch code thành exe có 2 tiến trình:

  • biên dịch các file code ví dụ .cpp thành mã máy, ví dụ .o
  • liên kết mã máy từ các file .o thành file thực thi .exe, hoặc thư viện tĩnh .a/.lib, hoặc thư viện động .dll

ở bước 1 biên dịch, ko cần biết các hàm nó hoạt động ra sao, ví dụ gọi sqrt() thì nó ko cần biên dịch mã của sqrt() mà nó chỉ “goto” tới phần mã máy của sqrt() ở chỗ khác. Chỗ nào thì bước 2 liên kết sẽ quyết định

ví dụ biên dịch file main.cpp có curl:
g++ -c main.cpp -Ipath/to/curl/include
-c là chỉ biên dịch, ko liên kết
-I<path> là bảo g++ cho thêm <path> vào thư mục header khi nó cần tìm ví dụ #include <curl.h>
khi này g++ sẽ biên dịch main.cpp thành mã máy main.o, và ví dụ trong main có gọi curl_easy_init() thì main.o chả có chứa mã máy gì của curl_easy_init() init cả, chỉ có chứa 1 cái địa chỉ ảo của curl_easy_init() và goto địa chỉ này. Sở dĩ nó biết có hàm curl_easy_init() là vì trong curl.h có chứa definition của hàm này, còn hàm này nó làm cái gì thì khi biên dịch nó ko biết vì trong main.cpp ko có implementation của hàm này. Khi gọi curl_easy_init() trong main.cpp thì nó chỉ biên dịch ra đơn giản là lưu địa chỉ hiện tại trong main, đi tới địa chỉ của curl_easy_init, và thực thi tiếp các mã lệnh trong curl_easy_init, và hy vọng khi thực hiện xong các mã lệnh của curl_easy_init này nó sẽ trở lại địa chỉ trước đó trong main :V

khi liên kết thành file .exe:
liên kết động:
g++ main.o -Lpath/to/curl/lib -lcurl
-L<path> (chữ L hoa) tương tự như -I, cho thêm <path> vào các thư mục mà g++ sẽ tìm kiếm khi liên kết các mã máy lại với nhau.
-lcurl (chữ L thường)
g++ lúc này sẽ đi tìm địa chỉ của curl_easy_init(), nếu quên cho -lcurl vào thì nó sẽ báo là ko thấy địa chỉ tới implementation của curl_easy_init: undefined reference to _imp__curl_easy_init, còn nếu cho vào thì nó sẽ biết mà tìm địa chỉ này trong file libcurl.dll.a: chữ -l được “chuyển hóa” thành lib<tên thư viện>.dll.a, curl là tên thư viện nên file chứa địa chỉ cần tìm sẽ là libcurl.dll.a, và nó sẽ tìm trong lib của g++ hoặc path/to/curl/lib mà mình đã thêm vào trong flag -L ở trên. Tìm ra rồi nó sẽ chuyển địa chỉ ảo trong main.o thành địa chỉ tương đối và nhét vào file .exe. Tương đối ở đây là tương đối với địa chỉ của dll libcurl.dll. Vì là liên kết động nên mỗi lần bấm file .exe này lên Windows sẽ tự động tìm libcurl.dll ở folder chứa file exe, nếu ko thấy thì nó sẽ tìm tiếp trong các folder trong PATH environment, nếu tìm thấy thì Windows sẽ load file dll này lên chạy cùng với file exe, và địa chỉ thật của curl_easy_init() sẽ được xác định là địa chỉ của libcurl.dll + địa chỉ tương đối trong file exe.

còn liên kết tĩnh:
g++ main.o libcurl.a -Lpath/to/curl/lib
y hệt như khi liên kết mấy file .o lại với nhau g++ file1.o file2.o ... Khi này toàn bộ mã máy của curl_easy_init() sẽ được nhét vào file .exe, và địa chỉ tuyệt đối của nó cũng được xác định nằm trong file exe, khi bật lên thì Windows nó ko cần tìm file dll nào hết vì mã của nó ở trong file exe rồi.

liên kết tĩnh thì chương trình chạy hơi hơi lẹ hơn liên kết động, nhưng 1 số license như LGPL ko cho phép liên kết tĩnh, trừ phi phải open source toàn bộ chương trình :V :V

lần sau cứ thấy lỗi undefined reference to _imp__... là tự hiểu nó ko tìm thấy mã máy của hàm ..., nghĩa là quên thêm -l<tên thư viện> trong phần liên kết rồi.

để cho dễ hình dung thì cứ nghĩ các file .cpp là 1 chương của 1 cuốn sách, khi viết sách thì ta viết từng chương, chương này có thể nhắc tới (refer) các phần trong chương khác trong cùng cuốn sách (liên kết tĩnh) hoặc các phần trong các chương của cuốn sách khác (liên kết động). Khi đóng gói 1 cuốn sách thì ta nối/liên kết các chương lại với nhau, sắp xếp có thứ tự, nếu “liên kết tĩnh” thì ta có thể tính ra “địa chỉ tuyệt đối”/số trang hiện tại của các phần trong các chương khác dễ dàng. Còn “liên kết động” thì ta cũng làm tương tự như liên kết tĩnh như khi đọc sách hay chạy chương trình :V thì ta phải mở 2 cuốn sách lên mà đọc, và khi đọc phần này của cuốn khác thì phải quay đầu qua cuốn đó mà đọc nên chậm hơn đọc trong 1 cuốn sách :V Khi nối các chương lại với nhau, người nối sẽ kiểm tra các reference trong các chương, nếu tìm ko thấy reference sẽ la lên undefined reference to _imp__... nghĩa là tôi có thể nối nhưng người đọc ko thể hiểu phần này nghĩa là gì vì đâu có reference tới trang nào đâu :V
khác biệt của liên kết động và tĩnh có nhiều, ví dụ cái lợi của liên kết động là khi mua 3 cuốn sách A,B,C cùng nhắc tới cuốn sách X thì ta chỉ cần mua 1 cuốn X là đủ, còn liên kết tĩnh thì 3 cuốn sách AX,BX,CX coi như ta phải mua sách X 3 lần vì X nó gắn kèm trong 3 cuốn :V Cái bất tiện là đọc chậm hơn vì phải ngó qua ngó lại :V cái thiệt hại là mua quyển X ko đúng edition ví dụ đòi edition 3 năm 2019 mà đi mua X edition 1 năm 2000 thì ko đúng số trang, đọc A,B,C ko được :V

5 Likes

Phần link library bác viết chi tiết quá, em tò mò nên có thử add lại cái lib đó trong Code Block để xem được không thì có một vấn đề thế này, em add lib libcurl.a vào Build Option -> Linker Setting -> Link libraries, thêm -DCURL_STATICLIB vào chỗ “other linker option” thì lúc build lại báo một lỗi là “cannot find -lcurl” , em không hiểu tại sao lại báo lỗi -lcurl vì rõ ràng em đã add lib là static , thực ra em quay lại thử cái Code Block vì em khá khó chịu vì chưa giải quyết đc cái này, nếu lần sau có gặp lại thì mình lại ko biết làm sao, do công việc em chủ yếu làm trên linux nên VS em hơi ít dùng do vậy em muốn biết cách add các lib vào project.

Bác có dùng cái vcpkg trên linux không vậy, em có thử cài trên linux và install thử cái lib curl thì thấy nó sinh ra khá nhiều folder, em tìm trong đó thì thấy có các lib.a, folder include…em có thử lấy folder include và lib.a ra dùng thì lúc build hiện ra khá nhiều lỗi, các lỗi undefined referance tới các file.c dùng để build ra lib.a (vd s3_both.c:-1: error: undefined reference to `X509_certificate_type’ s3_both.c), không biết cách em add có đúng cách sử dụng không nữa, thanks bác nhiều ạ

trên linux thì có libcurl-dev gì đó mà, sao lại cần build từ source làm gì :V

-D... là tương đương với #define, nó thuộc về bước biên dịch chứ không phải bước liên kết, cho nó vào flag liên kết là sai rồi :V

1 Like
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?