PDA

View Full Version : حرفه ای: مشکل اجرا شدن فایل اجرایی در لینوکس در صورت استفاده از Lib (حل شده)



کامبیز اسدزاده
پنج شنبه 01 مرداد 1394, 09:13 صبح
سلام

از دوستان با تجربه یه مشکلی برام پیش اومد یهویی کلا هنگ کردم !
یه مثال ساده میزنم تا سریع منظورم از مشکلی که هست رو برسونم بنابراین بر فرض اینکه من فایل .h و .cpp رو میسازم و مثلا یک تابعی رو فراخوانی میکنم تا ازش استفاده کنم به صورت زیر :


در فیل .h هیدر به این صورت در نظر بگیریم



#ifndef ME_H
#define ME_H


int sum(int x, int y);


#endif




و در فایل cpp به این صورت بدنه رو تکمیل کنیم...


#include "Me.h"
#include <iostream>


int sum(int x, int y)
{
return x + y;
}


حالا این تابع ساده رو در تابع اصلی main اجرا کنیم :


#include <iostream>
#include "Me.h"


int main() {


std::cout << sum(3, 4);

getchar();
return 0;
}



شاید با خودتون میگید این که مشکلی نداره ! بله مشکلی نداره از هر جهتی مثال رو ساده زدم که روشن باشه این کد کاملا جواب میده و کارهم میکنه مخصوصا در ویندوز هیچ مشکلی نداره اما هنگام کامپایل در لینوکس اجرا میشه ولی وقتی خارج از محیط IDE اجراش میکنیم اجرا نمیشه! جالب اینجاست زمانی اجرا میشه که در فایل اصلی و تابع main فایل Me.cpp رو اینکلود کنم ! یا اینکه دقیقا کدی که تو .cpp نوشتم رو در خود اون .h بنویسم در اینصورت مشکلی نداره !!!! مشکل اصلی اینه به هیچ عنوان با اینکلود کردن فایل .h برنامه اجرا نمیشه !!!!!!!! :متعجب:

این چه بدبختیه ؟ مشکل چیه؟ تاحالا به همچین چیز ریز و حساسی برنخورده بودم ! یعنی در لینوکس مستقیما باید فایلی رو اینکلود کنیم که بدنه تابع توش تکمیل شده !؟! آخه با عقل جور در نمیاد !!! میتونه نوعی عدم پشتیبانی از هیدر در سیستم های UNIX باشه ؟!

راه حل؟ نظرات و پشنهادات ؟ اگه این مشکل حل نشه با این حساب باید من دونه دونه بنده هارو توی هیدر بنویسم یا بجای .h وردارم دونه دونه .cpp هارو اینکلود کنم که با عقل منطق جور در نمیاد و صحیح هم نیست.

:متعجب:

کامبیز اسدزاده
پنج شنبه 01 مرداد 1394, 10:00 صبح
عذر میخوام، چه جوری تابع رو فراخوانی میکنید؟
اینجا اشتباه تایپ کرده بودم به صورت زیره :


std::cout << sum(3, 4);

Desaghi
پنج شنبه 01 مرداد 1394, 11:21 صبح
این را هم اضافه کنید:istdio.hوg++ main.cpp sumfun.cpp -I

negative60
پنج شنبه 01 مرداد 1394, 11:52 صبح
سلام

از دوستان با تجربه یه مشکلی برام پیش اومد یهویی کلا هنگ کردم !
یه مثال ساده میزنم تا سریع منظورم از مشکلی که هست رو برسونم بنابراین بر فرض اینکه من فایل .h و .cpp رو میسازم و مثلا یک تابعی رو فراخوانی میکنم تا ازش استفاده کنم به صورت زیر :


در فیل .h هیدر به این صورت در نظر بگیریم



#ifndef ME_H
#define ME_H


int sum(int x, int y);


#endif




و در فایل cpp به این صورت بدنه رو تکمیل کنیم...


#include "Me.h"
#include <iostream>


int sum(int x, int y)
{
return x + y;
}


حالا این تابع ساده رو در تابع اصلی main اجرا کنیم :


#include <iostream>
#include "Me.h"


int main() {


std::cout << sum(3, 4);

getchar();
return 0;
}



شاید با خودتون میگید این که مشکلی نداره ! بله مشکلی نداره از هر جهتی مثال رو ساده زدم که روشن باشه این کد کاملا جواب میده و کارهم میکنه مخصوصا در ویندوز هیچ مشکلی نداره اما هنگام کامپایل در لینوکس اجرا میشه ولی وقتی خارج از محیط IDE اجراش میکنیم اجرا نمیشه! جالب اینجاست زمانی اجرا میشه که در فایل اصلی و تابع main فایل Me.cpp رو اینکلود کنم ! یا اینکه دقیقا کدی که تو .cpp نوشتم رو در خود اون .h بنویسم در اینصورت مشکلی نداره !!!! مشکل اصلی اینه به هیچ عنوان با اینکلود کردن فایل .h برنامه اجرا نمیشه !!!!!!!! :متعجب:

این چه بدبختیه ؟ مشکل چیه؟ تاحالا به همچین چیز ریز و حساسی برنخورده بودم ! یعنی در لینوکس مستقیما باید فایلی رو اینکلود کنیم که بدنه تابع توش تکمیل شده !؟! آخه با عقل جور در نمیاد !!! میتونه نوعی عدم پشتیبانی از هیدر در سیستم های UNIX باشه ؟!

راه حل؟ نظرات و پشنهادات ؟ اگه این مشکل حل نشه با این حساب باید من دونه دونه بنده هارو توی هیدر بنویسم یا بجای .h وردارم دونه دونه .cpp هارو اینکلود کنم که با عقل منطق جور در نمیاد و صحیح هم نیست.

:متعجب:

مشکلی نداره در ترمينال هم نتيجه 7 چاپ ميشه تنها مشکل کامپايل نشدن برنامه به دليل اينکلود نکردن stdio.h بود که اون هم مربوط به تابع getchar() هست.

کامبیز اسدزاده
پنج شنبه 01 مرداد 1394, 11:56 صبح
مشکلی نداره در ترمينال هم نتيجه 7 چاپ ميشه تنها مشکل کامپايل نشدن برنامه به دليل اينکلود نکردن stdio.h بود که اون هم مربوط به تابع getchar() هست.

نتیجه رو میده همه چیز درسته ولی مشکل اصلی اینه خارج از محیط IDE کار نمیکنه.
همین مثال رو که زدم در محیط Qt Creator ایجاد میکنم ترو تمیز کار میکنه ولی وقتی هیدر رو تو فایل main وارد میکنم خارج از محیط Qt Creator اجرا نمیشه که نمیشه ! بدبختیه اصلی اینه و اگرنا تو خود محیط Debug قشنگ جواب میده.

جالب اینجاست چیز خاصی هم اینکلود نمیکنم که بگم کتابخانه ی خاصی ه که باید کتار فایل باشه یا از این حرفا...
اگه دارید شما هم یه تستی بکنید...

البته به این نکته اشاره کنم من این تابع رو به صورت Library یا DLL بیلد میکنم و بعد وارد پروژه میکنم و میخوام ازش استفاده کنم...
یعنی مشکل برمیگرده به LIB بودنه این تابع !

یعنی همین تابع رو میارم تو پروژه ای که main توش هست باز نویسی میکنم ایرادی نداره... مشکل برمیگرده به Lib بودنه تابع از نوع extern C هم میگیرمش بازم همین آشه همین کاسه !

حامد مصافی
پنج شنبه 01 مرداد 1394, 12:05 عصر
شما سه فایل در این پروژه دارید
main.cpp
Me.h
Me.cpp

فایل main.cpp که کامپایل می‌شود فایل Me.h هم که اینکلود شده پس تمام سورس آن به main.cpp منتقل می‌شود اما فایل Me.cpp کامپایل نمی‌شود به همین دلیل دسترسی به تابع تعریف شده در داخل آن وجود ندارد. این فایل هم باید همراه با بقیه فایل‌ها کامپایل شود (قانون کلی: همه فایل‌های cpp باید به کامپایلر معرفی شوند)

برای ادامه مبجث لطفاً شیوه کامپایل رو هم بگو، مستقیم از خط فرمان استفاده می‌کنی یا از ابزاری مانند cmake استفاده می‌کنی؟(در حالت اول پست شماره ۳ راه حلیه که باید ازش استفاده کنی)

کامبیز اسدزاده
پنج شنبه 01 مرداد 1394, 12:12 عصر
شما سه فایل در این پروژه دارید
main.cpp
Me.h
Me.cpp

فایل main.cpp که کامپایل می‌شود فایل Me.h هم که اینکلود شده پس تمام سورس آن به main.cpp منتقل می‌شود اما فایل Me.cpp کامپایل نمی‌شود به همین دلیل دسترسی به تابع تعریف شده در داخل آن وجود ندارد. این فایل هم باید همراه با بقیه فایل‌ها کامپایل شود (قانون کلی: همه فایل‌های cpp باید به کامپایلر معرفی شوند)

برای ادامه مبجث لطفاً شیوه کامپایل رو هم بگو، مستقیم از خط فرمان استفاده می‌کنی یا از ابزاری مانند cmake استفاده می‌کنی؟(در حالت اول پست شماره ۳ راه حلیه که باید ازش استفاده کنی)

من ابتدا یک lib میسازم که توش همین تابع با فایل های .h و .cpp هستش هیچ خبری هم از main تو این پروژه از نوع lib وچود نداره توی فایل .pro هم کانفیگش درسته به صورت زیر :


TEMPLATE = lib


بعد این تابع رو با همون روش Add library و External به صورت زیر انجام میدم :


win32:CONFIG(release, debug|release): LIBS += -L$$PWD/debug-x86/release/ -lTestlib
else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/debug-x86/debug/ -lTestlib
else:unix: LIBS += -L$$PWD/debug-x86/ -lTestlib


INCLUDEPATH += $$PWD/../MyLib/Testlib
DEPENDPATH += $$PWD/../MyLib/Testlib




یعنی تقریبا کامپایل کردن lib و افزودنش بدونه ایراد هست و با خود Qt Creator بیلدش میکنم..
در محیط Creator اجراش میکنم کار میکنه ولی خارج از محیط...کار نمیکنه البته فایل libTestlib.so و .. رو هم کنار فایل اجرایی کپی میکنم.

دیگه ذهنم به جایی نمیرسه ! :لبخند:

negative60
پنج شنبه 01 مرداد 1394, 12:34 عصر
نتیجه رو میده همه چیز درسته ولی مشکل اصلی اینه خارج از محیط IDE کار نمیکنه.
همین مثال رو که زدم در محیط Qt Creator ایجاد میکنم ترو تمیز کار میکنه ولی وقتی هیدر رو تو فایل main وارد میکنم خارج از محیط Qt Creator اجرا نمیشه که نمیشه ! بدبختیه اصلی اینه و اگرنا تو خود محیط Debug قشنگ جواب میده.

جالب اینجاست چیز خاصی هم اینکلود نمیکنم که بگم کتابخانه ی خاصی ه که باید کتار فایل باشه یا از این حرفا...
اگه دارید شما هم یه تستی بکنید...

البته به این نکته اشاره کنم من این تابع رو به صورت Library یا DLL بیلد میکنم و بعد وارد پروژه میکنم و میخوام ازش استفاده کنم...
یعنی مشکل برمیگرده به LIB بودنه این تابع !

یعنی همین تابع رو میارم تو پروژه ای که main توش هست باز نویسی میکنم ایرادی نداره... مشکل برمیگرده به Lib بودنه تابع از نوع extern C هم میگیرمش بازم همین آشه همین کاسه !

همين مثالی که قرار داديد رو تست کردم عرض کردم برنامه رو تو ترمينال اجرا ميکنم يعنی خارج از محيط IDE و بدون مشکل کار ميکنه.
با لايبری هم مشکلی نداره, اين پروژه که ضمينه کردم بدون مشکل خارج از IDE هم درست اجرا ميشه.

کامبیز اسدزاده
پنج شنبه 01 مرداد 1394, 12:39 عصر
همين مثالی که قرار داديد رو تست کردم عرض کردم برنامه رو تو ترمينال اجرا ميکنم يعنی خارج از محيط IDE و بدون مشکل کار ميکنه.
با لايبری هم مشکلی نداره, اين پروژه که ضمينه کردم بدون مشکل خارج از IDE هم درست اجرا ميشه.

خب روی MyApp کلیک میکنم کار نمیکنه !
اگه رو سیستم شما کار میکنه رو مال من نه با این حساب مشکل به چی برمیگرده !!!!

negative60
پنج شنبه 01 مرداد 1394, 12:52 عصر
نکته: اين لايبری که تو فايل ضمينه قرار داره تو ubunto 64 bit کامپايل شده, قطا اگر ubuntu شما 32 باشه کار نميکنه
خوب فکر کنم از اول هم برنامه شما مشکلی نداشته!:لبخندساده:
رو برنامه های کنسول تو لينوکس دابل کليک کنيد برنامه اجرا ميشه اما صفحه اي باز نميشه بايد از ترمينال برنامه رو باز کنيد، مثل cmd در ويندوز بايد فقط مسير برنامه رو بنويسيد

حامد مصافی
پنج شنبه 01 مرداد 1394, 14:09 عصر
در لینوکس بر خلاف ویندوز فایل های لایبرری در کنار فایل اجرایی شناسایی نمیشوند، ابتدا یک فایل متنی همنام فایل اجرایی و با پسوند sh ایجاد کن و محتویات زیر رو در اون کپی کن:

#!/bin/sh
appname=`basename $0 | sed s,\.sh$,,`

dirname=`dirname $0`
tmp="${dirname#?}"

if [ "${dirname%$tmp}" != "/" ]; then
dirname=$PWD/$dirname
fi
LD_LIBRARY_PATH=/usr/lib/i386-linux-gnu/qt5:${LD_LIBRARY_PATH}
export LD_LIBRARY_PATH
$dirname/$appname "$@"
سپس به این فایل جدید مجوز اجرایی بده و به جای فایل اجرایی اونو احرا کن.

پ.ن: به همین دلیل برنامه هایی مثل کیوت کریتور، وایبر، اکلیپس و... چنین فایلی دارند

کامبیز اسدزاده
پنج شنبه 01 مرداد 1394, 14:29 عصر
نکته: اين لايبری که تو فايل ضمينه قرار داره تو ubunto 64 bit کامپايل شده, قطا اگر ubuntu شما 32 باشه کار نميکنه
خوب فکر کنم از اول هم برنامه شما مشکلی نداشته!:لبخندساده:

رو برنامه های کنسول تو لينوکس دابل کليک کنيد برنامه اجرا ميشه اما صفحه اي باز نميشه بايد از ترمينال برنامه رو باز کنيد، مثل cmd در ويندوز بايد فقط مسير برنامه رو بنويسيد

ابنتویی که روش تست میکنم 64 بیتی هست و حتی کامپایلر نسخه 64 بیتی رو دارم.


در لینوکس بر خلاف ویندوز فایل های لایبرری در کنار فایل اجرایی شناسایی نمیشوند، ابتدا یک فایل متنی همنام فایل اجرایی و با پسوند sh ایجاد کن و محتویات زیر رو در اون کپی کن:

#!/bin/sh
appname=`basename $0 | sed s,\.sh$,,`

dirname=`dirname $0`
tmp="${dirname#?}"

if [ "${dirname%$tmp}" != "/" ]; then
dirname=$PWD/$dirname
fi
LD_LIBRARY_PATH=/usr/lib/i386-linux-gnu/qt5:${LD_LIBRARY_PATH}
export LD_LIBRARY_PATH
$dirname/$appname "$@"
سپس به این فایل جدید مجوز اجرایی بده و به جای فایل اجرایی اونو احرا کن.

پ.ن: به همین دلیل برنامه هایی مثل کیوت کریتور، وایبر، اکلیپس و... چنین فایلی دارند

مشکل به روش ساخت فایل .sh و اجرا از طریق ترمینال حل شد دوستان عزیز ممنون بابت راهنمایی.:تشویق::قلب:
واییییی یعنی 2 روزه بیهوده دارم کلنجار میرم روی کد ها ! :قهقهه: خوبه سوال کردم و اگرنا باید کله پروژه رو زیرو میکردم ! :لبخند:
ولی بر این اساس باید هر سری از طریق ترمینال اجرا کنیم برنامه رو ! راه حلی برای این مورد نداریم ؟

حامد مصافی
پنج شنبه 01 مرداد 1394, 14:32 عصر
نه مگه کیوت کریتور یا وایبرو از ترمینال اجرا میکنیم؟
اگه این فایل شل رو نمیخوای راه حل اینه که فایل so در مسیر lib سیستم کپی بشه

کامبیز اسدزاده
پنج شنبه 01 مرداد 1394, 14:39 عصر
نه مگه کیوت کریتور یا وایبرو از ترمینال اجرا میکنیم؟
اگه این فایل شل رو نمیخوای راه حل اینه که فایل so در مسیر lib سیستم کپی بشه

اینم حل شد رفت ، بسیار عالی و تشکر مجدد.