Phát hiện hệ điều hành bằng hai thủ thuật đơn giản:
- Đầu tiên là biến môi trường
OS
- Sau đó,
uname
lệnh
ifeq ($(OS),Windows_NT) # is Windows_NT on XP, 2000, 7, Vista, 10...
detected_OS := Windows
else
detected_OS := $(shell uname) # same as "uname -s"
endif
Hoặc một cách an toàn hơn, nếu không có trên Windows và uname
không có sẵn:
ifeq ($(OS),Windows_NT)
detected_OS := Windows
else
detected_OS := $(shell sh -c 'uname 2>/dev/null || echo Unknown')
endif
Ken Jackson đề xuất một giải pháp thay thế thú vị nếu bạn muốn phân biệt Cygwin / MinGW / MSYS / Windows. Xem câu trả lời của anh ấy trông như thế:
ifeq '$(findstring ;,$(PATH))' ';'
detected_OS := Windows
else
detected_OS := $(shell uname 2>/dev/null || echo Unknown)
detected_OS := $(patsubst CYGWIN%,Cygwin,$(detected_OS))
detected_OS := $(patsubst MSYS%,MSYS,$(detected_OS))
detected_OS := $(patsubst MINGW%,MSYS,$(detected_OS))
endif
Sau đó, bạn có thể chọn những thứ liên quan tùy thuộc vào detected_OS
:
ifeq ($(detected_OS),Windows)
CFLAGS += -D WIN32
endif
ifeq ($(detected_OS),Darwin) # Mac OS X
CFLAGS += -D OSX
endif
ifeq ($(detected_OS),Linux)
CFLAGS += -D LINUX
endif
ifeq ($(detected_OS),GNU) # Debian GNU Hurd
CFLAGS += -D GNU_HURD
endif
ifeq ($(detected_OS),GNU/kFreeBSD) # Debian kFreeBSD
CFLAGS += -D GNU_kFreeBSD
endif
ifeq ($(detected_OS),FreeBSD)
CFLAGS += -D FreeBSD
endif
ifeq ($(detected_OS),NetBSD)
CFLAGS += -D NetBSD
endif
ifeq ($(detected_OS),DragonFly)
CFLAGS += -D DragonFly
endif
ifeq ($(detected_OS),Haiku)
CFLAGS += -D Haiku
endif
Ghi chú:
Lệnh uname
giống như uname -s
vì tùy chọn -s
( --kernel-name
) là mặc định. Xem tại sao uname -s
tốt hơnuname -o
.
Việc sử dụng OS
(thay vì uname
) đơn giản hóa thuật toán nhận dạng. Bạn vẫn có thể sử dụng duy nhất uname
, nhưng bạn phải xử lý if/else
các khối để kiểm tra tất cả các biến thể của MinGW, Cygwin, v.v.
Biến môi trường OS
luôn được đặt thành "Windows_NT"
trên các phiên bản Windows khác nhau (xem %OS%
biến môi trường trên Wikipedia ).
Một thay thế OS
là biến môi trường MSVC
(nó kiểm tra sự hiện diện của MS Visual Studio , xem ví dụ sử dụng Visual C ++ ).
Dưới đây tôi cung cấp một ví dụ hoàn chỉnh bằng cách sử dụng make
và gcc
để xây dựng thư viện dùng chung: *.so
hoặc *.dll
tùy thuộc vào nền tảng. Ví dụ đơn giản nhất có thể để dễ hiểu hơn.
Để cài đặt make
và gcc
trên Windows, xem Cygwin hoặc MinGW .
Ví dụ của tôi dựa trên năm tệp
├── lib
│ └── Makefile
│ └── hello.h
│ └── hello.c
└── app
└── Makefile
└── main.c
Nhắc nhở: Makefile
được thụt lề bằng cách sử dụng bảng . Thận trọng khi sao chép-dán bên dưới các tập tin mẫu.
Hai Makefile
tập tin
1. lib/Makefile
ifeq ($(OS),Windows_NT)
uname_S := Windows
else
uname_S := $(shell uname -s)
endif
ifeq ($(uname_S), Windows)
target = hello.dll
endif
ifeq ($(uname_S), Linux)
target = libhello.so
endif
#ifeq ($(uname_S), .....) #See https://stackoverflow.com/a/27776822/938111
# target = .....
#endif
%.o: %.c
gcc -c $< -fPIC -o $@
# -c $< => $< is first file after ':' => Compile hello.c
# -fPIC => Position-Independent Code (required for shared lib)
# -o $@ => $@ is the target => Output file (-o) is hello.o
$(target): hello.o
gcc $^ -shared -o $@
# $^ => $^ expand to all prerequisites (after ':') => hello.o
# -shared => Generate shared library
# -o $@ => Output file (-o) is $@ (libhello.so or hello.dll)
2. app/Makefile
ifeq ($(OS),Windows_NT)
uname_S := Windows
else
uname_S := $(shell uname -s)
endif
ifeq ($(uname_S), Windows)
target = app.exe
endif
ifeq ($(uname_S), Linux)
target = app
endif
#ifeq ($(uname_S), .....) #See https://stackoverflow.com/a/27776822/938111
# target = .....
#endif
%.o: %.c
gcc -c $< -I ../lib -o $@
# -c $< => compile (-c) $< (first file after :) = main.c
# -I ../lib => search headers (*.h) in directory ../lib
# -o $@ => output file (-o) is $@ (target) = main.o
$(target): main.o
gcc $^ -L../lib -lhello -o $@
# $^ => $^ (all files after the :) = main.o (here only one file)
# -L../lib => look for libraries in directory ../lib
# -lhello => use shared library hello (libhello.so or hello.dll)
# -o $@ => output file (-o) is $@ (target) = "app.exe" or "app"
Để tìm hiểu thêm, hãy đọc tài liệu Biến tự động như được chỉ ra bởi cfi .
Mã nguồn
- lib/hello.h
#ifndef HELLO_H_
#define HELLO_H_
const char* hello();
#endif
- lib/hello.c
#include "hello.h"
const char* hello()
{
return "hello";
}
- app/main.c
#include "hello.h" //hello()
#include <stdio.h> //puts()
int main()
{
const char* str = hello();
puts(str);
}
Tòa nhà
Sửa lỗi sao chép-dán Makefile
(thay thế khoảng trắng hàng đầu bằng một bảng).
> sed 's/^ */\t/' -i */Makefile
Các make
lệnh là như nhau trên cả hai nền tảng. Đầu ra đã cho là trên các HĐH giống Unix:
> make -C lib
make: Entering directory '/tmp/lib'
gcc -c hello.c -fPIC -o hello.o
# -c hello.c => hello.c is first file after ':' => Compile hello.c
# -fPIC => Position-Independent Code (required for shared lib)
# -o hello.o => hello.o is the target => Output file (-o) is hello.o
gcc hello.o -shared -o libhello.so
# hello.o => hello.o is the first after ':' => Link hello.o
# -shared => Generate shared library
# -o libhello.so => Output file (-o) is libhello.so (libhello.so or hello.dll)
make: Leaving directory '/tmp/lib'
> make -C app
make: Entering directory '/tmp/app'
gcc -c main.c -I ../lib -o main.o
# -c main.c => compile (-c) main.c (first file after :) = main.cpp
# -I ../lib => search headers (*.h) in directory ../lib
# -o main.o => output file (-o) is main.o (target) = main.o
gcc main.o -L../lib -lhello -o app
# main.o => main.o (all files after the :) = main.o (here only one file)
# -L../lib => look for libraries in directory ../lib
# -lhello => use shared library hello (libhello.so or hello.dll)
# -o app => output file (-o) is app.exe (target) = "app.exe" or "app"
make: Leaving directory '/tmp/app'
Chạy
Ứng dụng này yêu cầu phải biết thư viện chia sẻ ở đâu.
Trên Windows, một giải pháp đơn giản là sao chép thư viện nơi có ứng dụng:
> cp -v lib/hello.dll app
`lib/hello.dll' -> `app/hello.dll'
Trên các hệ điều hành giống Unix, bạn có thể sử dụng LD_LIBRARY_PATH
biến môi trường:
> export LD_LIBRARY_PATH=lib
Chạy lệnh trên Windows:
> app/app.exe
hello
Chạy lệnh trên các hệ điều hành giống Unix:
> app/app
hello
PROCESSOR_ARCHITECTURE
envvar dường như được ảo hóa tùy thuộc vào quá trình là 32 bit hay 64 bit. Vì vậy, nếu bạnmake
là 32 bit và bạn đang cố gắng xây dựng một ứng dụng 64 bit, nó sẽ thất bại. Sử dụng kết hợp vớiPROCESSOR_ARCHITEW6432
làm việc cho tôi (xem cái này và cái kia )